2229: [Zjoi2011]最小割
Time Limit: 10 Sec Memory Limit: 259 MBDescription
小白在图论课上学到了一个新的概念——最小割,下课后小白在笔记本上写下了如下这段话: “对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点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
1
5 0
1
0
5 0
1
0
Sample Output
10
【数据范围】
对于100%的数据 T<=10,n<=150,m<=3000,q<=30,x在32位有符号整数类型范围内。
图中两个点之间可能有多条边
【数据范围】
对于100%的数据 T<=10,n<=150,m<=3000,q<=30,x在32位有符号整数类型范围内。
图中两个点之间可能有多条边
这里用到了一个知识点叫最小割树
一个n点的图最多有n-1个最小割
我们可以将一个图变成一个树
则这张图中任意两点的最小割就是最小割树上两点之间最短的割
操作很简单
每次任选两点跑最小割, 分为集合s, t
在两个集合中递归下去
1 #include <iostream> 2 #include <cstdio> 3 #include <queue> 4 #include <cstring> 5 #include <algorithm> 6 #define LL long long 7 8 using namespace std; 9 10 queue<int> q; 11 const LL inf = 1e18; 12 const int MAXN = 200; 13 const int MAXM = 3e3 + 10; 14 int TT, Q; 15 int n, m; 16 int S, T; 17 LL u, v, c; 18 int cnt = 0; 19 20 LL ans[MAXN][MAXN]; 21 bool vis[MAXN]; 22 int a[MAXN]; 23 int temp[MAXN]; 24 int h[MAXN]; 25 int head[MAXN]; 26 27 struct edge { 28 int v; 29 LL c; 30 int next; 31 } g[MAXM * 2]; 32 33 void addedge(int u, int v, int w) 34 { 35 g[cnt].v = v; 36 g[cnt].c = w; 37 g[cnt].next = head[u]; 38 head[u] = cnt++; 39 } 40 41 inline LL read() 42 { 43 LL x = 0, w = 1; char ch = 0; 44 while(ch < '0' || ch > '9') { 45 if(ch == '-') { 46 w = -1; 47 } 48 ch = getchar(); 49 } 50 while(ch >= '0' && ch <= '9') { 51 x = x * 10 + ch - '0'; 52 ch = getchar(); 53 } 54 return x * w; 55 } 56 57 void restore() 58 { 59 for(int j = 0; j <= cnt; j++) { 60 g[j].c = g[j ^ 1].c = ((g[j].c + g[j ^ 1].c) >> 1); 61 } 62 } 63 64 bool BFS() 65 { 66 memset(h, -1, sizeof h); 67 h[S] = 0; 68 q.push(S); 69 while(!q.empty()) { 70 int t = q.front(); 71 q.pop(); 72 for(int j = head[t]; j != -1; j = g[j].next) { 73 int to = g[j].v; 74 if(h[to] == -1 && g[j].c) { 75 h[to] = h[t] + 1; 76 q.push(to); 77 } 78 } 79 } 80 if(h[T] == -1) { 81 return false; 82 } 83 return true; 84 } 85 86 LL DFS(int x, LL f) 87 { 88 int used = 0; 89 if(x == T) { 90 return f; 91 } 92 for(int j = head[x]; j != -1; j = g[j].next) { 93 int to = g[j].v; 94 if(h[to] == h[x] + 1 && g[j].c) { 95 LL w = f - used; 96 w = DFS(to, min(w, g[j].c)); 97 used += w; 98 g[j].c -= w, g[j ^ 1].c += w; 99 if(used == f) { 100 break; 101 } 102 } 103 } 104 if(!used) { 105 h[x] = -1; 106 } 107 return used; 108 } 109 110 void search(int x) 111 { 112 vis[x] = 1; 113 for(int j = head[x]; j != -1; j = g[j].next) { 114 int to = g[j].v; 115 if(!vis[to] && g[j].c) { 116 search(to); 117 } 118 } 119 } 120 121 void solve(int l, int r) 122 { 123 //cout<<l<<" "<<r<<endl; 124 if(l == r) { 125 return; 126 } 127 restore(); 128 S = a[l], T = a[r]; 129 LL flow = 0; 130 while(BFS()) { 131 flow += DFS(S, inf); 132 } 133 memset(vis, 0, sizeof vis); 134 search(S); 135 int L = l, R = r; 136 for(int i = l; i <= r; i++) { 137 if(vis[a[i]]) { 138 temp[L++] = a[i]; 139 } else { 140 temp[R--] = a[i]; 141 } 142 } 143 for(int i = 1; i <= n; i++) { 144 if(vis[i]) { 145 for(int j = 1; j <= n; j++) { 146 if(!vis[j]) { 147 ans[i][j] = ans[j][i] = min(ans[i][j], flow); 148 } 149 } 150 } 151 } 152 for(int i = l; i <= r; i++) { 153 a[i] = temp[i]; 154 } 155 solve(l, L - 1), solve(R + 1, r); 156 } 157 158 void open() 159 { 160 freopen("mincut1.in", "r", stdin); 161 //freopen("mincut.out", "w", stdout); 162 } 163 164 void close() 165 { 166 fclose(stdin); 167 fclose(stdout); 168 } 169 int main() 170 { 171 //open(); 172 TT = read(); 173 while(TT--) { 174 memset(ans, 0x3f, sizeof ans); 175 memset(head, -1, sizeof head); 176 cnt = 0; 177 n = read(), m = read(); 178 for(int i = 1; i <= n; i++) { 179 a[i] = i; 180 } 181 for(int i = 1; i <= m; i++) { 182 u = read(), v = read(), c = read(); 183 addedge(u, v, c); 184 addedge(v, u, c); 185 } 186 solve(1, n); 187 Q = read(); 188 while(Q--) { 189 int sum = 0; 190 LL x = read(); 191 for(int i = 1; i <= n; i++) { 192 for(int j = i + 1; j <= n; j++) { 193 if(ans[i][j] <= x) { 194 sum++; 195 } 196 } 197 } 198 printf("%d ", sum); 199 } 200 printf(" "); 201 } 202 // close(); 203 return 0; 204 } 205 206 207 /* 208 1 209 5 0 210 1 211 0 212 213 */