题目意思:给出一个无向图,n个顶点,n-1条边。每条边有权值w,表示流量。
流量:本来我实在没理解题目样例的解释,后来问了一位大佬的解,秒懂了.其实边权可以理解成水管的粗细,水能流多少。
比如1->4-3 首先1->4可以通过13的水,由于4->3水管只有5的大小,所以1-4-3只能流出5.
再比如1->4->5 之前1->4->3 已经流出了5 那么1->4->5 剩下还有8,粗细为10的可以全部通过,所以1->4->5流出是8.
题目要求的是,以某个点为根,计算根到所有叶子节点的流量和
最后再取最大值
好了题意应该理解了。。。。
分析:这是一道换根dp题,思路就是换根之后和换根之前的贡献差异,推出转移方程即可。
首先分成2种情况:
第一种换根节点为叶子节点(比较特殊)
如图所示:
第二种换根节点不是叶子节点(常规情况)
如图所示:
这里注意的是,如果用一个数组来存结果,那么中间变动的值不能改变。详细看代码细节。
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <string> #include <vector> #include <map> #include <queue> #include <deque> #include <set> #include <stack> #include <cctype> #include <cmath> #include <cassert> using namespace std; typedef long long ll; const ll mod=1000000007; ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;} ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;} const int N=200000+100; int t; int n; int x,y,z; int head[N],tot; int isleaf[N];//判断是不是叶子节点 int f[N];//每个节点总贡献 struct Edge { int e; int to; int w;//权值 }edge[N<<1]; void add_edge(int u,int v,int val) { tot++; edge[tot].e=v; edge[tot].to=head[u]; edge[tot].w=val; ++isleaf[u];//每次加边的时候,由于我们正反2次加,所以叶子节点最后的isleaf值一定是2 ++isleaf[v]; head[u]=tot; } void init() {//初始化函数 memset(head,0,sizeof(head)); tot=0; for(int i=0;i<N;i++) { edge[i].e=0; edge[i].to=0; edge[i].w=0; } memset(isleaf,0,sizeof(isleaf)); memset(f,0,sizeof(f)); } void dfs(int u,int fa) {//第一次dfs,计算从1为根的所有点的流量 for(int i=head[u];i!=0;i=edge[i].to) { int v=edge[i].e; int w=edge[i].w; if(v==fa)continue; dfs(v,u); //如果是叶子节点,直接加上流量,不是叶子节点,和当前权值取最小值即可 if(isleaf[v]==2)f[u]+=w; else f[u]+=min(f[v],w); } } void dfs2(int u,int fa) { for(int i=head[u];i!=0;i=edge[i].to) { int v=edge[i].e; int w=edge[i].w; if(v==fa)continue; //把根换做v if(isleaf[v]==2)f[v]+=w;//叶子节点的时候 else { int k=f[u]-min(f[v],w);//用一个临时变量存一下,不能直接改变. // f[u]-=min(f[v],w);这样写是错的 f[v]+=min(w,k); } dfs2(v,u); } } int main() { scanf("%d",&t); while(t--) { init(); scanf("%d",&n); for(int i=0;i<n-1;i++) { scanf("%d%d%d",&x,&y,&z); add_edge(x,y,z); add_edge(y,x,z); } // for(int i=1;i<=n;i++) // { // if(isleaf[i]==2) // { // printf("%d is leap\n",i); // } // else // { // printf("%d is not leap\n",i); // } // } dfs(1,0); // for(int i=1;i<=n;i++) // { // printf("f[%d]:%d\n",i,f[i]); // } // printf("f[1]:%d\n",f[1]); dfs2(1,0); // for(int i=1;i<=n;i++) // { // printf("f[%d]:%d\n",i,f[i]); // } int maxx=-1e9; for(int i=1;i<=n;i++) { maxx=max(maxx,f[i]); } printf("%d\n",maxx); } return 0; }