题意转换:假设f(x)为x节点到叶子节点的最大流量,求最大f(x):x属于1~n
dp[u]表示每个节点u往儿子方向流的最大流量。
对于全部不为叶子节点u,深度往下传的流量最优为dp[u]+=min(dp[u_son],flow(u,u_son)),有点类似于贪心的想法。
叶子节点x为dp[x]=flow(x_fa,x);
然后考虑每个节点通过父节点的边到其他叶子节点的流量,由于我们已经预处理了全部dp[],所以对于节点u和其父节点u_fa,u节点通过其父节点流入其他的叶子节点的流量可以是min(flow(u,u_fa),dp[u]-min(dp[v],flow(u,u_fa)));不断更新dp即可,还是比较模板的题了。
#include <cctype> #include <cfloat> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <algorithm> #include <deque> #include <fstream> #include <functional> #include <iomanip> #include <iostream> #include <istream> #include <iterator> #include <list> #include <map> #include <ostream> #include <queue> #include <set> #include <sstream> #include <stack> #include <string> #include <utility> #include <vector> #include <unordered_map> #include <unordered_set> using namespace std; const int maxn=3e5+10; typedef pair<int,int> P; vector<P> G[maxn]; long long val[maxn],ans; void dfs(int u, int fa,long long sum) { val[u]=0; for (int i=0; i<G[u].size(); i++) { int v=G[u][i].first; if (v==fa) continue; long long k=G[u][i].second; dfs(v,u,k); val[u]+=min(val[v],k); } if (G[u].size()==1) val[u]=sum; } void solve(int u, int fa, long long c, long long sum) { val[u]+=min(sum,c); ans=max(ans,val[u]); for (int i=0; i<G[u].size(); i++) { int v=G[u][i].first; if (v==fa) continue; long long k=G[u][i].second; solve(v,u,k,val[u]-min(k,val[v])); } } int main() { int t; scanf("%d",&t); while (t--) { int n; scanf("%d",&n); for (int i=1; i<=n; i++) G[i].clear(); for (int i=1; i<n; i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); G[a].push_back(P(b,c)); G[b].push_back(P(a,c)); } if (n==1) printf("0\n"); else if (n==2) printf("%d\n",G[1][0].second); else { ans=0; for (int i=1; i<=n; i++) { if (G[i].size()>1) { dfs(i,0,0); break; } } solve(1,0,0,0); printf("%lld\n",ans); } } return 0; }