
原题链接
https://www.luogu.com.cn/problem/P3931
解题思路
根据题意,本题与最小割问题极为相似,根据最大流最小割定理,本题可转化为求网络最大流。
还未学习该知识的,请先学习,然后建议先写模板题练习一下。
首先,提醒一个雷区!题目给的是一个无向图,故我们需要先从树根开始对这个无向图进行dfs预处理,把无向边转换成有向边。(WA 20分的绝大多数都忽略了这一点,包括我)
然后,一个网络流图不仅要有源点(即树的根节点),还要有汇点。我们假设n+1即为汇点,让所有的叶子节点都伸出一条指向n+1的有向边(这个可以在dfs预处理时顺便处理一下,而且要记得建反向边)。
题目要求任何叶子节点都和根节点不连通,而这个条件恰恰和汇点和源点不连通是等价的(因为所有叶子节点都和汇点连通,故但凡有任何一个叶子节点和根节点连通,汇点和源点都是连通的)。
至此,我们已经完成了构造,接下来问题就只剩下求网络流图的最大流了。这里有多种算法可以选择,我使用的是dinic算法,具体实现不再赘述。在存图时我采取的是vector存图,下面的代码供参考。
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| #include<cstdio> #include<cstring> #include<vector> #include<queue> #include<algorithm> #define N 100005 #define I 0x3f3f3f3f using namespace std; struct road{int to,w;}; struct edge{int to,w;}e[N<<2]; vector<road> g[N]; vector<int> v[N]; int n,s,t,t1,t2,t3,cnt,ans,d[N]; void pre(int x,int fa) { if(g[x].size()==1&&g[x][0].to==fa) { v[x].push_back(cnt); e[cnt].to=t; e[cnt++].w=I; v[t].push_back(cnt); e[cnt].to=x; e[cnt++].w=0; return; } for(int i=0;i<g[x].size();i++) { int to=g[x][i].to,w=g[x][i].w; if(to==fa)continue; v[x].push_back(cnt); e[cnt].to=to; e[cnt++].w=w; v[to].push_back(cnt); e[cnt].to=x; e[cnt++].w=0; pre(to,x); } } bool bfs() { queue<int> q; memset(d,0,sizeof(d)); d[s]=1; q.push(s); while(q.size()) { int now=q.front(); q.pop(); for(int i=0;i<v[now].size();i++) { int temp=v[now][i]; int to=e[temp].to,w=e[temp].w; if(!d[to]&&w) { d[to]=d[now]+1; q.push(to); } } } return d[t]; } int dfs(int now,int minn) { if(now==t)return minn; for(int i=0;i<v[now].size();i++) { int temp=v[now][i]; int to=e[temp].to,w=e[temp].w; if(d[to]==d[now]+1&&w) { int res=dfs(to,min(minn,w)); if(res) { e[temp].w-=res; e[temp^1].w+=res; return res; } } } return 0; } int main() { scanf("%d%d",&n,&s); t=n+1; for(int i=1;i<n;i++) { scanf("%d%d%d",&t1,&t2,&t3); g[t1].push_back({t2,t3}); g[t2].push_back({t1,t3}); } pre(s,s); while(bfs()) ans+=dfs(s,I); printf("%d",ans); return 0; }
|