前言:我DP太菜了——明明考了一道很像的题,我还不会QAQ(WA的一声哭了出来)
正文
首先看到这道题,你可以用一个比较暴力的办法——每次换一个点扫一遍,但是这样会超时,所以我们可以换一种想法——用玄学的DP来解决这类问题
这时你可以来扫两边: 一边先存每个点向子树流向的流量大小,然后用DP再向后推,动态转移方程见程序。你可叫他:二次扫描和换根法
注意点:
1.流量每次应该取最小的,因为你是在三次元,没有河流在没支流的情况下会在经过流量小的后突然变大
2.这题有多组数据
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int MAXN=2*1e5+5; 6 struct ziji{ 7 int ver,nxt,edge; 8 #define ver(i) mn[i].ver 9 #define nxt(i) mn[i].nxt 10 #define edge(i) mn[i].edge 11 }mn[MAXN<<1]; 12 int deg[MAXN],head[MAXN],n,m,tot,d[MAXN]; 13 bool vis[MAXN];int root=1,x,y,z,fa[MAXN]; 14 //fa[i]是以i为根节点时,i可以流向整个树的最大流量 15 //deg[i]是每个点入读个数 16 //d[i]是每个点在第一次扫过后,可以知道的流量 17 void add(int x,int y,int z){ 18 ver(++tot)=y,nxt(tot)=head[x]; 19 head[x]=tot,edge(tot)=z; 20 } 21 void dp(int x){ 22 //从x出发,流向子树的流量的最大值 23 vis[x]=1;d[x]=0; 24 for(register int i=head[x];i;i=nxt(i)){ 25 int y=ver(i); 26 if(vis[y]) continue;dp(y); 27 if(deg[y]==1) d[x]+=edge(i); 28 //如果这个点只有一个点可以到这里,就只能加上edge[i] 29 else d[x]+=min(d[y],edge(i)); 30 //否则,这个点就要在从上面流过来的流量和这条边可以走的最大流量取min 31 //由三次元可以知道,流量不会凭空变大,只会越来越小 32 } 33 } 34 void dfs(int x){ 35 //求以x为根时,x可以向整个子树去流的最大流量 36 vis[x]=1; 37 for(register int i=head[x];i;i=nxt(i)){ 38 int y=ver(i);if(vis[y]) continue; 39 if(deg[x]==1) fa[y]=d[y]+edge(i); 40 //如果再向下走时,下面的点只有这一个入度 41 //那么这个点的流量就是这个点向他自己的子树和向他的父节点的流量和 42 else fa[y]=d[y]+min(fa[x]-min(d[y],edge(i)),edge(i)); 43 //否则,就是他流向子树的流量与 44 //理论上可以流向父亲节点的流量和三次元中实际上可以流的较小值之和 45 //理论上流向父节点的最小值:父节点流向其他节点的流量和它可以在流向父节点的较小值 46 dfs(y); 47 } 48 } 49 int main(){ 50 int t;scanf("%d",&t); 51 while(t--){ 52 memset(vis,0,sizeof(vis));memset(d,0,sizeof(d)); 53 memset(deg,0,sizeof(deg));memset(fa,0,sizeof(fa)); 54 memset(head,0,sizeof(head));memset(mn,0,sizeof(mn)); 55 scanf("%d",&n);root=1;tot=0; 56 if(n==0||n==1){printf("0\n");continue;} 57 for(register int i=1;i<n;i++){ 58 scanf("%d%d%d",&x,&y,&z); 59 add(x,y,z);add(y,x,z); 60 deg[x]++,deg[y]++; //统计出入度 61 } 62 dp(root);fa[root]=d[root]; 63 memset(vis,0,sizeof(vis)); 64 dfs(root);int ans=0; 65 for(register int i=1;i<=n;i++) ans=max(ans,fa[i]); 66 printf("%d\n",ans); 67 } 68 return 0; 69 }