2229: [Zjoi2011]最小割(最小割樹)
阿新 • • 發佈:2019-01-08
Description
小白在圖論課上學到了一個新的概念——最小割,下課後小白在筆記本上寫下了如下這段話: “對於一個圖,某個對圖中結點的劃分將圖中所有結點分成兩個部分,如果結點s,t不在同一個部分中,則稱這個劃分是關於s,t的割。 對於帶權圖來說,將所有頂點處在不同部分的邊的權值相加所得到的值定義為這個割的容量,而s,t的最小割指的是在關於s,t的割中容量最小的割” 現給定一張無向圖,小白有若干個形如“圖中有多少對點它們的最小割的容量不超過x呢”的疑問,小藍雖然很想回答這些問題,但小藍最近忙著挖木塊,於是作為仍然是小藍的好友,你又有任務了。
Input
輸入檔案第一行有且只有一個正整數T,表示測試資料的組數。 對於每組測試資料, 第一行包含兩個整數n,m,表示圖的點數和邊數。 下面m行,每行3個正整數u,v,c(1<=u,v<=n,0<=c<=106),表示有一條權為c的無向邊(u,v) 接下來一行,包含一個整數q,表示詢問的個數 下面q行,每行一個整數x,其含義同題目描述。
Output
對於每組測試資料,輸出應包括q行,第i行表示第i個問題的答案。對於點對(p,q)和(q,p),只統計一次(見樣例)。
兩組測試資料之間用空行隔開。
Sample Input
15 0
1
0
Sample Output
10【資料範圍】
對於100%的資料 T<=10,n<=150,m<=3000,q<=30,x在32位有符號整數類型範圍內。
圖中兩個點之間可能有多條邊 解題思路: 最小割樹,用於解決全域性任意點間的最小割。 考慮對於全域性任意兩個點的最小割將圖分成的兩部分,假如說我們在這兩部分之間畫一條分界線。
1 #include<queue> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 const int oo=0x3f3f3f3f; 6 struct pnt{ 7 int hd; 8 int lyr; 9 int now; 10 bool vis; 11 }p[1000]; 12 struct ent{ 13 int twd; 14 int lst; 15 int vls; 16 int his; 17 }e[1000000]; 18 int cnt; 19 int n,m; 20 int s,t; 21 int app[200]; 22 int tmp[200]; 23 int ans[151][151]; 24 std::queue<int>Q; 25 void ade(int f,int t,int v) 26 { 27 cnt++; 28 e[cnt].twd=t; 29 e[cnt].vls=v; 30 e[cnt].his=v; 31 e[cnt].lst=p[f].hd; 32 p[f].hd=cnt; 33 return ; 34 } 35 bool Bfs(void) 36 { 37 while(!Q.empty())Q.pop(); 38 for(int i=1;i<=n;i++) 39 p[i].lyr=0; 40 p[s].lyr=1; 41 Q.push(s); 42 while(!Q.empty()) 43 { 44 int x=Q.front(); 45 Q.pop(); 46 for(int i=p[x].hd;i;i=e[i].lst) 47 { 48 int to=e[i].twd; 49 if(p[to].lyr==0&&e[i].vls>0) 50 { 51 p[to].lyr=p[x].lyr+1; 52 if(to==t) 53 return true; 54 Q.push(to); 55 } 56 } 57 } 58 return false; 59 } 60 int Dfs(int x,int fll) 61 { 62 if(x==t) 63 return fll; 64 for(int& i=p[x].now;i;i=e[i].lst) 65 { 66 int to=e[i].twd; 67 if(p[to].lyr==p[x].lyr+1&&e[i].vls>0) 68 { 69 int ans=Dfs(to,std::min(fll,e[i].vls)); 70 if(ans>0) 71 { 72 e[i].vls-=ans; 73 e[((i-1)^1)+1].vls+=ans; 74 return ans; 75 } 76 } 77 } 78 return 0; 79 } 80 int Dinic() 81 { 82 int ans=0; 83 while(Bfs()) 84 { 85 for(int i=1;i<=n;i++) 86 p[i].now=p[i].hd; 87 int dlt; 88 while(dlt=Dfs(s,oo)) 89 ans+=dlt; 90 } 91 return ans; 92 } 93 void dfs(int x) 94 { 95 if(p[x].vis) 96 return ; 97 p[x].vis=true; 98 for(int i=p[x].hd;i;i=e[i].lst) 99 { 100 int to=e[i].twd; 101 if(e[i].vls>0) 102 dfs(to); 103 } 104 return ; 105 } 106 void Build(int l,int r) 107 { 108 if(l==r) 109 return ; 110 s=app[l],t=app[r]; 111 for(int i=1;i<=cnt;i+=4) 112 { 113 e[i].vls=e[i].his; 114 e[i+1].vls=e[i+1].his; 115 e[i+2].vls=e[i+2].his; 116 e[i+3].vls=e[i+3].his; 117 } 118 int tmf=Dinic(); 119 for(int i=1;i<=n;i++) 120 p[i].vis=false; 121 dfs(s); 122 for(int i=1;i<=n;i++) 123 if(p[i].vis) 124 for(int j=1;j<=n;j++) 125 if(!p[j].vis) 126 ans[i][j]=ans[j][i]=std::min(ans[i][j],tmf); 127 int i=l-1,j=r+1; 128 for(int k=l;k<=r;k++) 129 if(p[app[k]].vis) 130 tmp[++i]=app[k]; 131 else 132 tmp[--j]=app[k]; 133 for(int k=l;k<=r;k++) 134 app[k]=tmp[k]; 135 Build(l,i); 136 Build(j,r); 137 return ; 138 } 139 int main() 140 { 141 // freopen("a.in","r",stdin); 142 int T; 143 scanf("%d",&T); 144 while(T--) 145 { 146 scanf("%d%d",&n,&m); 147 cnt=0; 148 for(int i=1;i<=n;i++) 149 app[i]=i, 150 p[i].hd=0; 151 memset(ans,0x3f,sizeof(ans)); 152 for(int i=1;i<=m;i++) 153 { 154 int a,b,c; 155 scanf("%d%d%d",&a,&b,&c); 156 ade(a,b,c); 157 ade(b,a,c); 158 } 159 Build(1,n); 160 int q; 161 scanf("%d",&q); 162 while(q--) 163 { 164 int x; 165 scanf("%d",&x); 166 int ansl=0; 167 for(int i=1;i<n;i++) 168 for(int j=i+1;j<=n;j++) 169 if(ans[i][j]<=x) 170 ansl++; 171 printf("%d\n",ansl); 172 } 173 puts(""); 174 } 175 return 0; 176 }