2017 ACM/ICPC Asia Regional Qingdao Online
题意:
给定一个网络图,求该网络中割边数量最少的最小割集。
思路:
脑洞方法,在建图时将每条边的权值w改成w*(m+1)+1,最后求得的最大流除以(m+1)就是原图的最大流,模上(m+1)就是割边最少的最小割集的边数量。可以分析一下得知,(m+1)是为了保证模数在边数叠加之后仍然是模数,每条边权多+1正好符合了一条割边去代替多条割边的功能,想一下就明白了。。
还有一个过不了的算法,即在求得最大流之后,将所有满流的边权设为1,不满流的边权设为inf,然后跑一边最大流就是答案,但是却过不了所有数据。
但我认为这题本就是一道不能做的题目,再看下面的样例:
1
7 10
1 2
1 2 1
1 3 1
1 4 1
2 5 1
3 5 1
4 5 1
1 6 5
6 5 5
5 7 8
6 7 1000
对于第二种方法,跑最大流如果没用到1000这条边,那么跑出来的最小割的边数是2,而如果用到了这条边呢,最小的边数就是4。
但是第一种方法呢,跑出来的可能会是1和4(过的代码跑出1),但很明显这组样例的ans不可能是1的。
其实就是原题HDU-3987,但在这题两种方法都会过,狂套各种版本都不过真的很爆炸= =。
代码:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <vector>
#include <cstdio>
#include <queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 205;
const int maxm = 2005;
struct node{int u, v, w, next;} edge[maxm];
int dis[maxn], pre[maxn], rec[maxn], head[maxn], block[maxn];
int n, m, no, s, t;
queue<int> q;
inline void init()
{
no = 0;
memset(head, -1, sizeof head);
}
inline void add(int u, int v, int w)
{
edge[no].u = u; edge[no].v = v; edge[no].w = w;
edge[no].next = head[u]; head[u] = no++;
edge[no].u = v; edge[no].v = u; edge[no].w = 0;
edge[no].next = head[v]; head[v] = no++;
}
void reset(int S, int T)
{
memset(dis, 0x3f, sizeof dis);
memset(block, 0, sizeof block);
q.push(S); dis[S] = 0;
while(!q.empty())
{
int top = q.front(); q.pop();
for(int k = head[top]; k != -1; k = edge[k].next)
if(dis[edge[k].v] == inf && edge[k].w)
dis[edge[k].v] = dis[top]+1, q.push(edge[k].v);
}
}
int dinic(int S, int T)
{
int ans = 0, flow = inf, top = S;
reset(S, T); pre[S] = S;
while(dis[T] != inf)
{
int k, tmp;
for(k = head[top]; k != -1; k = edge[k].next)
{
if(edge[k].w && dis[edge[k].v]==dis[top]+1 &&
!block[edge[k].v]) break;
}
if(k != -1)
{
tmp = edge[k].v;
flow = min(flow, edge[k].w);
pre[tmp] = top, rec[tmp] = k;
top = tmp;
if(top == T)
{
ans += flow; tmp = -1;
for(; top != S; top = pre[top])
{
edge[rec[top]].w -= flow;
edge[rec[top]^1].w += flow;
if(!edge[rec[top]].w) tmp = top;
}
flow = inf;
if(tmp != -1)
{
top = pre[tmp];
for(; top != S; top = pre[top])
flow = min(flow, edge[rec[top]].w);
top = pre[tmp];
}
}
}
else
{
block[top] = 1;
top = pre[top];
if(block[S]) reset(S, T);
}
}
return ans;
}
void mapping()
{
int u, v, w;
for(int i = 1; i <= m; ++i)
{
scanf("%d %d %d", &u, &v, &w);
add(u, v, w*1001+1);
}
}
int main()
{
int tt; scanf("%d", &tt);
while(tt--)
{
scanf("%d %d", &n, &m);
scanf("%d %d", &s, &t);
init();
mapping();
printf("%d\n", dinic(s, t)%1001);
}
return 0;
}
继续加油~