(树dp)UVA - 12677 Join two kingdoms
Posted 惜取少年时
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(树dp)UVA - 12677 Join two kingdoms相关的知识,希望对你有一定的参考价值。
题意:两个国家A,B,分别有N座城市和Q座城市(1 ≤ N, Q ≤ 4 × 10^4),每个国家里的城市都是树形结构,每条边的权值都是1。现在要随机从两个国家中各选择一个城市来将两个国家连接起来,问连接起来的大国家里面的最长路的期望是多少。
解题思路:
涉及到树上的最大长度,很容易想到树的直径。首先分别求出两棵树的直径, 之后就很方便的可以求出树上每个结点只在树上走的最大距离。这样对于任意一个连法,假设链接了x\y,最大距离=max(两棵树的直径中的最大值,x在该树中最大距离+y在该树中最大距离+1)
减少时间复杂度可以通过排序距离的办法。
(代码非常丑……)
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <queue> 8 #include <set> 9 #include <map> 10 #include <list> 11 #include <stack> 12 #define mp make_pair 13 typedef long long ll; 14 typedef unsigned long long ull; 15 const int MAX=1e5+5; 16 const int INF=1e9+5; 17 const double M=4e18; 18 using namespace std; 19 const int MOD=1e9+7; 20 typedef pair<int,int> pii; 21 typedef pair<int,long long> pil; 22 const double eps=0.000000001; 23 int n; 24 vector<pii> edge[MAX],edge2[MAX]; 25 ll sum[MAX]; 26 int a,b; 27 ll c; 28 ll d[MAX],d2[MAX]; 29 bool vi[MAX]; 30 int lo1,lo2,lo3,lo4; 31 int oh,oh2; 32 int findlong(int st) 33 { 34 memset(vi,false,sizeof(vi)); 35 vi[st]=true; 36 queue<pii> que; 37 int dismax=0,dis; 38 int an,tem; 39 que.push(mp(st,0)); 40 while(!que.empty()) 41 { 42 tem=que.front().first; 43 dis=que.front().second; 44 pii lin; 45 que.pop(); 46 for(int i=0;i<edge[tem].size();i++) 47 { 48 lin=edge[tem][i]; 49 if(!vi[lin.first]) 50 { 51 vi[lin.first]=true; 52 if(dismax<dis+lin.second) 53 { 54 dismax=dis+lin.second; 55 an=lin.first; 56 } 57 que.push(mp(lin.first,dis+lin.second)); 58 } 59 } 60 } 61 oh=dismax; 62 return an; 63 } 64 int findlong2(int st) 65 { 66 memset(vi,false,sizeof(vi)); 67 vi[st]=true; 68 queue<pii> que; 69 int dismax=0,dis; 70 int an,tem; 71 que.push(mp(st,0)); 72 while(!que.empty()) 73 { 74 tem=que.front().first; 75 dis=que.front().second; 76 pii lin; 77 que.pop(); 78 for(int i=0;i<edge2[tem].size();i++) 79 { 80 lin=edge2[tem][i]; 81 if(!vi[lin.first]) 82 { 83 vi[lin.first]=true; 84 if(dismax<dis+lin.second) 85 { 86 dismax=dis+lin.second; 87 an=lin.first; 88 } 89 que.push(mp(lin.first,dis+lin.second)); 90 } 91 } 92 } 93 oh2=dismax; 94 return an; 95 } 96 void dfs(int st) 97 { 98 memset(vi,false,sizeof(vi)); 99 vi[st]=true; 100 queue<pii> que; 101 int tem; 102 int dis; 103 que.push(mp(st,0LL)); 104 while(!que.empty()) 105 { 106 tem=que.front().first; 107 dis=que.front().second; 108 pii lin; 109 que.pop(); 110 d[tem]=max(d[tem],(ll)dis); 111 for(int i=0;i<edge[tem].size();i++) 112 { 113 lin=edge[tem][i]; 114 if(!vi[lin.first]) 115 { 116 vi[lin.first]=true; 117 que.push(mp(lin.first,dis+lin.second)); 118 } 119 } 120 } 121 } 122 void dfs2(int st) 123 { 124 memset(vi,false,sizeof(vi)); 125 vi[st]=true; 126 queue<pii> que; 127 int tem; 128 int dis; 129 que.push(mp(st,0LL)); 130 while(!que.empty()) 131 { 132 tem=que.front().first; 133 dis=que.front().second; 134 pii lin; 135 que.pop(); 136 d2[tem]=max(d2[tem],(ll)dis); 137 for(int i=0;i<edge2[tem].size();i++) 138 { 139 lin=edge2[tem][i]; 140 if(!vi[lin.first]) 141 { 142 vi[lin.first]=true; 143 que.push(mp(lin.first,dis+lin.second)); 144 } 145 } 146 } 147 } 148 ll finan; 149 int main() 150 { 151 int n,q; 152 while(~scanf("%d %d",&n,&q)) 153 { 154 oh=oh2=0; 155 for(int i=1;i<=n;i++) 156 d[i]=0LL,edge[i].clear(); 157 for(int i=1;i<=q;i++) 158 d2[i]=0LL,edge2[i].clear(); 159 for(int i=1;i<n;i++) 160 { 161 scanf("%d%d",&a,&b); 162 edge[a].push_back(mp(b,1)); 163 edge[b].push_back(mp(a,1)); 164 } 165 for(int i=1;i<q;i++) 166 { 167 scanf("%d%d",&a,&b); 168 edge2[a].push_back(mp(b,1)); 169 edge2[b].push_back(mp(a,1)); 170 } 171 if(n==1) 172 lo1=lo2=1; 173 if(n>1) 174 { 175 lo1=findlong(1); 176 lo2=findlong(lo1); 177 } 178 if(q==1) 179 lo3=lo4=1; 180 if(q>1) 181 { 182 lo3=findlong2(1); 183 lo4=findlong2(lo3); 184 } 185 dfs(lo1);dfs(lo2); 186 dfs2(lo3);dfs2(lo4); 187 sort(d+1,d+1+n); 188 sort(d2+1,d2+1+q); 189 for(int i=1;i<=n;i++) 190 ++d[i]; 191 sum[0]=0LL; 192 for(int i=1;i<=q;i++) 193 sum[i]=sum[i-1]+d2[i]; 194 ll idx=q+1; 195 ll len=max(ll(oh),ll(oh2)); 196 ll re=0; 197 for(int i=1;i<=n;i++) 198 { 199 while(idx-1>=1&&d2[idx-1]+d[i]>len) 200 --idx; 201 if(idx==1) 202 re+=sum[q]+q*d[i]; 203 else if(idx==q+1) 204 re+=len*q; 205 else 206 { 207 re+=len*(idx-1); 208 re+=sum[q]-sum[idx-1]+(q-idx+1)*d[i]; 209 } 210 } 211 printf("%.3f\n",(double)re/n/q); 212 } 213 return 0; 214 }
以上是关于(树dp)UVA - 12677 Join two kingdoms的主要内容,如果未能解决你的问题,请参考以下文章
UVA 3942 -- Remember the Word (字典树+dp)
uva12093Protecting Zonk (树形DP)
UVA - 1218 Perfect Service(树形dp)