How Many to Be Happy? (最小生成树进一步理解 + 最小割)
最小生成树:MST性质(学习博客:here)
题解:我们想让某一条边一定是最小生成树中的边,只要找到任意一种点集的分配,使得这条边的两个顶点在不同的分配中且边权是连接这两个分配的所有边中最小的那一个。显然只有边权比它小的边才会影响它是不是在最小生成树中。于是我们可以只在图中保留边权小于当前边权的边,看看是否能找到一种点集的分配。显然当这个边的两个顶点在新图中仍然连通时,我们找不到这种分配,于是就需要砍掉若干边使两顶点不连通,于是题目就转化为了最小割问题。(来自大佬博客:here)
AC_Code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e5+10; 4 const int inf = 0x3f3f3f3f; 5 typedef long long ll; 6 7 8 struct node{ 9 ll to,nxt,w; 10 }e[maxn<<1]; 11 12 struct edge{ 13 ll u,v; 14 ll w; 15 bool operator < (const edge &o) const{ 16 return w<o.w; 17 } 18 }E[maxn]; 19 20 ll head[maxn],tot,dep[maxn]; 21 ll n,m; 22 ll S,T;//源点,汇点 23 24 void init(){ 25 memset(head,-1,sizeof(head)); 26 tot = 0; 27 } 28 29 void addedge(ll u,ll v,ll w){ 30 e[tot].to=v; e[tot].w=w; e[tot].nxt=head[u]; head[u]=tot++; 31 } 32 33 bool bfs(ll st,ll ed){ 34 memset(dep,-1,sizeof(dep)); 35 queue<ll>que; 36 while( !que.empty()) que.pop(); 37 que.push(st); 38 dep[st]=0; 39 ll u; 40 while( !que.empty()){ 41 u=que.front();que.pop(); 42 for(ll i=head[u]; ~i; i=e[i].nxt){ 43 ll v=e[i].to; 44 if( dep[v]==-1 && e[i].w>0 ){ 45 dep[v]=dep[u]+1; 46 que.push(v); 47 if( v==ed ) return true; 48 } 49 50 } 51 } 52 return dep[ed]!=-1; 53 } 54 55 ll dfs(ll st,ll ed,ll flow){ 56 if( st==ed || flow==0 ) return flow; 57 ll curr=0; 58 for(ll i=head[st];~i;i=e[i].nxt){ 59 ll v=e[i].to; 60 ll val=e[i].w; 61 if( dep[st]+1==dep[v] && val>0 ){ 62 ll d=dfs(v,ed,min(val,flow)); 63 if( d>0 ){ 64 e[i].w-=d;e[i^1].w+=d; 65 curr+=d;flow-=d; 66 if( flow==0 ) break; 67 } 68 } 69 } 70 if( curr==0 ) dep[st]=inf; 71 return curr; 72 } 73 74 ll Dinic(ll st,ll ed){ 75 for(ll i=0;i<=tot;i++) e[i].w = 1;//注意这里,因为e[i].w有被改动这里要初始化 76 ll flow=0; 77 while( bfs(st,ed) ){ 78 flow+=dfs(st,ed,inf); 79 } 80 return flow; 81 } 82 83 int main() 84 { 85 init(); 86 scanf("%lld%lld",&n,&m); 87 for(ll i=1;i<=m;i++){ 88 scanf("%lld%lld%lld",&E[i].u,&E[i].v,&E[i].w); 89 } 90 sort(E+1, E+1+m); 91 init(); 92 ll ans = 0; 93 ll r = 1; 94 for(ll i=1;i<=m;i++){ 95 while( E[r].w<E[i].w ){//注意要权值小于这条边才对这条边有影响,大于等于都没有影响 96 addedge(E[r].u, E[r].v, 1); 97 addedge(E[r].v, E[r].u, 1); 98 r ++ ; 99 } 100 S=E[i].u; 101 T=E[i].v; 102 ans += Dinic(S,T); 103 } 104 printf("%lld ",ans); 105 return 0; 106 }