几个问题不明白:
1. 对每条边乘以一个常数,在加1,经过这样处理后为什么能够求出边数最少的最小割。如果不乘以一个常数,直接加1,这样能否求出题目要求的最小割
2. 如何保证输出编号最小的最小割边集
问题1:
求最小边数的最小割,一种方法是对原始图求最大流,再将每条边容量加1,再求最大流,此时两次最大流的差值便是最小边数最小割的值。用这种方法能够通过此题的所有数据(对前两问),但我还没能形式化的给出证明,姑且认为它是对的......
标准做法中,对于每条边先乘以一个常数,再进行类似的处理。该种方法可以只求一次最大流就得出解,我想这也许是标准做法的原因所在
- #include <iostream>
- using namespace std;
- const int N = 40;
- const int M = 1010;
- long long ad[N][N], flow[N][N];
- int pre[N], q[N], head, tail, n;
- bool st[N];
- long long inc[N];
- struct edgeNode
- {
- int x, y;
- }edge[M];
- bool BFS(int src, int des)
- {
- int i, j, k;
- head = tail = 1;
- q[1] = src; inc[src] = (long long)(1047483647) * 2147483647;
- memset(pre, -1, sizeof(pre));
- while(head <= tail)
- {
- i = q[head++];
- for(j = 1; j <= n; j++)
- {
- if(pre[j] == -1 && ad[i][j] > flow[i][j])
- {
- pre[j] = i;
- inc[j] = min(inc[i], ad[i][j] - flow[i][j]);
- if(j == des) return true;
- q[++tail] = j;
- }
- }
- }
- return false;
- }
- long long Edmonds_Karp(int src, int des)
- {
- long long ans = 0;
- while(BFS(src, des))
- {
- ans += inc[des];
- for(int i = des; i != src; i = pre[i])
- {
- flow[pre[i]][i] += inc[des];
- flow[i][pre[i]] -= inc[des];
- }
- }
- return ans;
- }
- void DFS(int x)
- {
- st[x] = true;
- for(int i = 1; i <= n; i++)
- {
- if(ad[x][i] > flow[x][i] && !st[i])
- DFS(i);
- }
- }
- int main()
- {
- int i, j, k, t, m;
- freopen("milk6.in", "r", stdin);
- freopen("milk6.out", "w", stdout);
- scanf("%d%d",&n, &m);
- for(i = 0; i < m; i++)
- {
- scanf("%d%d%d",&j, &k, &t);
- edge[i] = (edgeNode){j, k};
- ad[j][k] += 500000 + i + (long long)500000 * 1001 * t;
- }
- long long ans = Edmonds_Karp(1, n);
- DFS(1);
- printf("%Ld %Ld/n", ans / (500000 * 1001) , (ans % (500000 * 1001)) / 500000 );
- for(i = 0; i < m; i++)
- if(st[edge[i].x] && ! st[edge[i].y])
- printf("%d/n",i + 1);
- scanf("%d",&n);
- return 0;
- }