1. 程式人生 > 實用技巧 >How Many to Be Happy? (最小生成樹進一步理解 + 最小割)

How Many to Be Happy? (最小生成樹進一步理解 + 最小割)

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\n",ans); 105 return 0; 106 }