1. 程式人生 > >bzoj2229: [Zjoi2011]最小割(分治最小割+最小割樹思想)

bzoj2229: [Zjoi2011]最小割(分治最小割+最小割樹思想)

flow n) www. 一道 兩個 urn 定義 mem ...

2229: [Zjoi2011]最小割

題目:傳送門

題解:

   一道非常好的題目啊!!!

   蒟蒻的想法:暴力枚舉點對跑最小割記錄...絕對爆炸啊....

   開始懷疑是不是題目騙人...難道根本不用網絡流???一看路牌....分治最小割?最小割樹?

   然後開始各種%論文...

   簡單來說吧,根據各種本蒟蒻不會證明的理論,那麽:所有最小割都不是完全獨立的,總共有n-1種(也就是樹上的n-1條邊)最小割 恰好和樹的定義一樣啊!

   那麽用一個solve遞歸函數來解決,一開始任意找兩個點作為st和ed來最小割,然後分治,在分開的兩個集合中繼續遞歸,用數組記錄答案

   以上都是根據邊所進行的離線操作,然後輸入Q個詢問,直接在線輸出答案就ok

代碼:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cmath>
  5 #include<algorithm>
  6 using namespace std;
  7 const int inf=999999999;
  8 struct node
  9 {
 10     int x,y,c,next,other;
 11 }a[210000];int len,last[110000];
 12 int
st,ed,n,m,T,ans; 13 void ins(int x,int y,int c) 14 { 15 int k1,k2; 16 k1=++len; 17 a[len].x=x;a[len].y=y;a[len].c=c; 18 a[len].next=last[x];last[x]=len; 19 20 k2=++len; 21 a[len].x=y;a[len].y=x;a[len].c=c; 22 a[len].next=last[y];last[y]=len; 23 24
a[k1].other=k2; 25 a[k2].other=k1; 26 } 27 int list[110000],h[110000],head,tail; 28 bool bt_h() 29 { 30 memset(h,0,sizeof(h));h[st]=1; 31 list[1]=st;head=1;tail=2; 32 while(head!=tail) 33 { 34 int x=list[head]; 35 for(int k=last[x];k;k=a[k].next) 36 { 37 int y=a[k].y; 38 if(h[y]==0 && a[k].c) 39 { 40 h[y]=h[x]+1; 41 list[tail++]=y; 42 } 43 } 44 head++; 45 } 46 if(h[ed])return true; 47 return false; 48 } 49 int find_flow(int x,int flow) 50 { 51 if(x==ed)return flow; 52 int s=0,t; 53 for(int k=last[x];k;k=a[k].next) 54 { 55 int y=a[k].y; 56 if(h[y]==h[x]+1 && a[k].c && s<flow) 57 { 58 s+=t=find_flow(y,min(a[k].c,flow-s)); 59 a[k].c-=t;a[a[k].other].c+=t; 60 } 61 } 62 if(s==0)h[x]=0; 63 return s; 64 } 65 int d[110000],num[110000],sta[110000],anss[1100][1100]; 66 void re_num(int x) 67 { 68 num[x]=1; 69 for(int k=last[x];k;k=a[k].next) 70 { 71 int y=a[k].y; 72 if(a[k].c && !num[y]) 73 re_num(y); 74 } 75 } 76 void solve(int l,int r) 77 { 78 if(l==r)return ; 79 for(int i=1;i<=len;i+=2)a[i].c=a[i+1].c=(a[i].c+a[i+1].c)>>1;//將邊權重置 80 st=d[l];ed=d[r];ans=0; 81 while(bt_h())ans+=find_flow(st,inf); 82 memset(num,0,sizeof(num)); 83 re_num(st); 84 for(int i=1;i<=n;i++) 85 if(num[i]) 86 for(int j=1;j<=n;j++) 87 if(!num[j]) 88 anss[i][j]=anss[j][i]=min(anss[i][j],ans); 89 int L=l,R=r; 90 for(int i=l;i<=r;i++) 91 { 92 if(num[d[i]])sta[L++]=d[i]; 93 else sta[R--]=d[i]; 94 } 95 for(int i=l;i<=r;i++)d[i]=sta[i]; 96 solve(l,L-1);solve(R+1,r);//分治,遞歸 97 } 98 int main() 99 { 100 scanf("%d",&T); 101 while(T--) 102 { 103 scanf("%d%d",&n,&m); 104 len=0;memset(last,0,sizeof(last));int x,y,c; 105 for(int i=1;i<=m;i++)scanf("%d%d%d",&x,&y,&c),ins(x,y,c); 106 for(int i=1;i<=n;i++)d[i]=i;memset(anss,63,sizeof(anss)); 107 solve(1,n); 108 int Q;scanf("%d",&Q); 109 while(Q--) 110 { 111 scanf("%d",&x);int cnt=0; 112 for(int i=1;i<=n;i++) 113 for(int j=i+1;j<=n;j++) 114 if(anss[i][j]<=x) 115 cnt++; 116 printf("%d\n",cnt); 117 } 118 printf("\n"); 119 } 120 return 0; 121 }

bzoj2229: [Zjoi2011]最小割(分治最小割+最小割樹思想)