题目的意思是给你一个棵树,每天边上有一个权值,现在要想根节点和每个叶子节点完全隔离开来,删除一些边,求最少需要删除的边权值综合是多少?
直接建模,以根节点为汇点,每个叶子节点连接虚拟源点流量无穷,树上的节点按原样建模就可以了。
最后跑一遍最大流等于最小割,完美解决。
召唤代码君:
#include <iostream> #include <cstdio> #include <cstring> #define maxn 20010 #define inf 1999999999 using namespace std; int first[maxn],to[maxn],c[maxn],next[maxn],N; int d[maxn],a[maxn],can[maxn],tag[maxn],TAG=520; int s,t,n,m,ans; int Q[maxn],bot,top; void _init() { N=-1,ans=0,s=0,t=m; for (int i=0; i<=n; i++) first[i]=-1,a[i]=0; } void edge(int U,int V,int W) { N++; to[N]=V,c[N]=W,next[N]=first[U],first[U]=N; } void _input() { int U,V,W; for (int i=1; i<n; i++) { scanf("%d%d%d",&U,&V,&W); edge(U,V,W),edge(V,U,W); a[U]++,a[V]++; } for (int i=1; i<=n; i++) if (a[i]==1 && i!=t) edge(s,i,inf),edge(i,s,0); } bool bfs() { TAG++; Q[bot=top=1]=t,d[t]=1,tag[t]=TAG; while (bot<=top) { int cur=Q[bot++]; for (int i=first[cur]; i!=-1; i=next[i]) { if (c[i^1]<=0 || tag[to[i]]==TAG) continue; d[to[i]]=d[cur]+1,Q[++top]=to[i],tag[to[i]]=TAG; //if (to[i]==s) return true; } } return tag[s]==TAG; return false; } int dfs(int cur,int num) { if (cur==t) return num; int tmp=num,k; for (int i=first[cur]; i!=-1; i=next[i]) { if (c[i]<=0 || tag[to[i]]!=TAG || d[to[i]]!=d[cur]-1 || can[to[i]]==TAG) continue; k=dfs(to[i],min(num,c[i])); if (k) c[i]-=k,c[i^1]+=k,num-=k; if (num==0) break; } if (num) can[cur]=TAG; return tmp-num; } int main() { while (scanf("%d%d",&n,&m)&&(n|m)) { _init(); _input(); while (bfs()) ans+=dfs(s,inf); printf("%d\n",ans); } return 0; }
原文地址:http://www.cnblogs.com/Canon-CSU/p/3826126.html