链接
http://acm.hdu.edu.cn/showproblem.php?pid=6214
题解
我这题就是直觉过题…其实我也不是很清楚为啥这么做…
就是把流量
×
2000
\times 2000
×2000,最大流模
2000
2000
2000就是答案
感性理解一下,跑完最大流之后流量为
0
0
0的边组成了一个割
最小割肯定是这个割的子集
我把流量乘以
2000
2000
2000是先保证了最大流,因为每个边只有一个
1
1
1,所以如果,某一次增广选择的路径使得割边数目不必要地
+
1
+1
+1,答案却不会
+
1
+1
+1
比如下面的图:
显然我把最左边边权为
2
2
2的边割掉就是最小边数的最小割
而还有一种割法是割掉两条
1
1
1的边,显然是非最优解
在我跑最大流的时候,第一次跑了
1001
1001
1001的流,使得答案
+
1
+1
+1
第二次跑的流是
1000
1000
1000,答案并没有增加
这只是一种特殊情况,因为
2
=
1
+
1
2=1+1
2=1+1,所以边权为
2
2
2的边就成了两条边权为
1
1
1的边的替代品
但是如果是下面这种情况
这里两次增广都是跑了
1001
1001
1001的流量
其实第二次是边权为
3
3
3的边拿出了
2000
2000
2000中的一个
1
1
1来给后面用
考虑把每次增广的流建立有向无环图,把那些对应参量网络中剩余容量为
0
0
0的边打上标记
那么一个最小割就是一些打标记的边的集合,删掉这个集合中的边能使得
S
S
S到达不了
T
T
T
如果想让边数最小,就可以做一些优化,让第一张图中那样的两个
1
1
1换成一个
2
2
2
应该解释的还不是很清楚(因为我自己都不清楚)
代码
#include <bits/stdc++.h>
#define maxn 210
#define maxe 3000
#define iinf 0x3f3f3f3f
using namespace std;
struct Graph2
{
int head[maxn], next[maxe], to[maxe], w[maxe], c[maxe], tot;
void clear(int N)
{
int i;
for(i=1;i<=N;i++)head[i]=0;
for(i=2;i<=tot;i++)next[i]=0;
tot=1;
}
void add(int a, int b, int ww, int cc){to[++tot]=b;next[tot]=head[a];w[tot]=ww;c[tot]=cc;head[a]=tot;}
void adde(int a, int b, int ww,int cc){add(a,b,ww,cc);add(b,a,-ww,0);}
}G;
struct ISAP
{
int S, T, last[maxn], d[maxn], num[maxn], Exit;
void init(int N)
{
for(int i=1;i<=N;i++)d[i]=num[i]=0;
num[0]=N;
Exit=0;
}
int dfs(Graph2& G, int pos, int in)
{
int flow=0, t;
if(pos==T)return in;
for(int &p=last[pos];p;p=G.next[p])
if(G.c[p] and d[G.to[p]]+1==d[pos])
{
flow+= t=dfs(G,G.to[p],min(in-flow,G.c[p]));
G.c[p]-=t, G.c[p^1]+=t;
if(Exit or in==flow)return flow;
}
Exit=--num[d[pos]]==0;
++num[++d[pos]];
last[pos]=G.head[pos];
return flow;
}
int maxflow(Graph2& G)
{
int ans(0);
while(!Exit)ans+=dfs(G,S,iinf);
return ans;
}
}isap;
int read(int x=0)
{
int c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-0x30;
return f*x;
}
int main()
{
int T(read()), n, m, i;
while(T--)
{
n=read(), m=read();
G.clear(n);
isap.init(n);
isap.S=read(), isap.T=read();
for(i=1;i<=m;i++)
{
auto u=read(), v=read(), w=read();
G.adde(u,v,0,w*2000+1);
}
auto ans=isap.maxflow(G);
cout<<ans%2000<<endl;
}
return 0;
}