题目大意:给定一个流量网络,网络的拓扑结构是无根树,定义A(k)以结点k为源点,其他叶子结点为汇点的最大流量,求的是A(k)的最大值(k=1,2,3……n)。
分析:这题跟树形DP专题Computer那题有点像,那题是距离,这题是流量,本质还是一样。从结点k流出的流量,要么经过儿子结点流出,要么经过父亲结点流出。先DP求每个结点经过儿子结点能流出的最大流量是s[k],在DP求每个结点经过父亲结点能流出的最大流量f[k]。最后结果是MAX(s[k]+f[k]),k=1,2,3...n。
s[k]=sum(MIN(s[i],wik)),i是k的儿子结点且不是叶子结点。s[k]=sum(wik),i是k的儿子结点且是叶子结点。
f[k]=MIN(wik,s[i]-MIN(wik,s[k])+f[i]),i是k的父亲结点且不是叶子结点。f[k]=wik,i是k的父亲结点且是叶子结点。
这题还有一个关键是如何保存结点之间的容量,并且可以根据结点快速访问,最开始我是用并查集求结点k到根结点的容量和(距离),最后超时了。后来用d2p[k]来保存结点k到其父亲结点的容量就AC了。
通过这题的训练,让我进一步理解了“用数组可以搞定一切数据结构”这句话。
1 #include <stdio.h> 2 #include <string.h> 3 #define N 200001 4 #define MAX(a,b) ((a)>(b)?(a):(b)) 5 #define MIN(a,b) ((a)<(b)?(a):(b)) 6 int u[2*N],v[2*N],w[2*N],next[2*N],first[N]; 7 int firstd[N],nextd[N]; 8 int p[N],d[N],d2p[N],dmax,n; 9 long long s[N],f[N],ans; 10 char vis[N]; 11 void addEdge(int a,int b,int l,int e) 12 { 13 u[e]=a,v[e]=b,w[e]=l; 14 next[e]=first[a]; 15 first[a]=e; 16 } 17 void dfs(int a,int fa) 18 { 19 int e,b; 20 d[a]=(fa==-1?0:d[fa]+1); 21 nextd[a]=firstd[d[a]]; 22 firstd[d[a]]=a; 23 dmax=MAX(dmax,d[a]); 24 for(e=first[a];e>=0;e=next[e]) 25 { 26 b=v[e]; 27 if(b!=fa) dfs(b,p[b]=a),vis[a]++,d2p[b]=w[e]; 28 } 29 } 30 void dp1() 31 { 32 int i,a,b,tmp; 33 memset(s,0,sizeof(s)); 34 for(i=dmax;i>0;i--) 35 { 36 for(b=firstd[i];b>=0;b=nextd[b]) 37 { 38 a=p[b]; 39 if(vis[b]==0) tmp=d2p[b]; 40 else tmp=MIN(s[b],d2p[b]); 41 s[a]+=tmp; 42 } 43 } 44 } 45 long long dp(int b) 46 { 47 int a=p[b],tmp; 48 if(f[b]!=-1) return f[b]; 49 if(a==-1) return f[b]=0; 50 if(vis[a]==0) return f[b]=d2p[b]; 51 if(vis[b]==0) tmp=d2p[b]; 52 else tmp=MIN(s[b],d2p[b]); 53 return f[b]=MIN(s[a]-tmp+dp(a),d2p[b]); 54 } 55 int main() 56 { 57 int t,i,a,b,l; 58 scanf("%d",&t); 59 while(t--) 60 { 61 scanf("%d",&n); 62 memset(first,-1,sizeof(first)); 63 memset(next,-1,sizeof(next)); 64 for(i=0;i<n-1;i++) 65 { 66 scanf("%d%d%d",&a,&b,&l),a--,b--; 67 addEdge(a,b,l,2*i); 68 addEdge(b,a,l,2*i+1); 69 } 70 p[0]=-1; 71 dmax=0; 72 memset(vis,0,sizeof(vis)); 73 vis[0]=-1; 74 memset(firstd,-1,sizeof(firstd)); 75 memset(nextd,-1,sizeof(nextd)); 76 dfs(0,-1); 77 dp1(); 78 memset(f,-1,sizeof(f)); 79 for(i=0;i<n;i++) dp(i); 80 ans=0; 81 for(i=0;i<n;i++) ans=MAX(ans,s[i]+f[i]); 82 printf("%lld\n",ans); 83 } 84 return 0; 85 }