此题与POJ3204值得对比一下,POJ3204是求割边,既关键边的数量,每一条关键边都会影响到最小割。而此题是求满足最小割的情况下,割边最要最少,求出最少的割边数量。做法是先跑一遍最大流,得到残留网络,对与该网络,如果流量为0(满流)则将流量改为1,否则改为无穷大,再跑一次最大流就得到答案---最少割边数。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define SIZE 1024
using namespace std;
typedef __int64 Int;
const Int inf = (Int)1<<60;
struct node
{
int to,next;
Int val;
}edge[SIZE*512];
node cp[SIZE*512];
int Case,N,M,sc,sk,pt;
Int ret;
int head[SIZE],idx;
int gap[SIZE],dis[SIZE];
void addnode(int from,int to,Int val)
{
edge[idx].to = to;
edge[idx].val = val;
edge[idx].next = head[from];
head[from] = idx++;
edge[idx].to = from;
edge[idx].val = 0;
edge[idx].next = head[to];
head[to] = idx++;
}
int dfs(int cur,Int cval)
{
if(cur == sk)
return cval;
int mindis = pt-1;
Int tval = cval;
for(int i=head[cur]; i!=-1; i=edge[i].next)
{
int to = edge[i].to;
if(edge[i].val > 0)
{
if(dis[to] + 1 == dis[cur])
{
Int val = dfs(to,min(edge[i].val,tval));
tval -= val;
edge[i].val -= val;
edge[i^1].val += val;
if(dis[sc] >= pt)
return cval-tval;
if(!tval)
break;
}
if(mindis > dis[to])
mindis = dis[to];
}
}
if(cval == tval)
{
--gap[dis[cur]];
if(!gap[dis[cur]])
dis[sc] = pt;
dis[cur] = mindis + 1;
++gap[dis[cur]];
}
return cval - tval;
}
void sap()
{
memset(gap,0,sizeof(gap));
memset(dis,0,sizeof(dis));
ret = 0;
gap[sc] = pt;
while(dis[sc] < pt)
ret += dfs(sc,inf);
}
void read()
{
scanf("%d%d",&N,&M);
sc = 0, sk = N-1, pt = sk+1;
idx = 0;
memset(head,-1,sizeof(head));
int s,e,d;
Int v;
for(int i=1; i<=M; i++)
{
scanf("%d%d%I64d%d",&s,&e,&v,&d);
addnode(s,e,v);
if(d)
addnode(e,s,v);
}
}
void work()
{
for(int i=0; i<idx; i++)
{
cp[i].to = edge[i].to;
cp[i].val = edge[i].val;
cp[i].next = edge[i].next;
}
int index = idx;
idx = 0;
memset(head,-1,sizeof(head));
for(int i=0; i<index; i+=2)
{
if(cp[i].val == 0) addnode(cp[i^1].to,cp[i].to,1);
else addnode(cp[i^1].to,cp[i].to,inf);
}
sap();
printf("%I64d\n",ret);
}
int main()
{
scanf("%d",&Case);
for(int ca = 1; ca <= Case; ca ++)
{
read();
sap();
printf("Case %d: ",ca);
work();
}
return 0;
}