题面
求最小割,并且在最小割的情况下求出最少要删去几条边
思路:
当然是最小割咯!
就是后一问不大好求
那怎么办呢? 似乎很复杂的样子
或许我们要在模板里改比较困难
那么我们就想办法在边上做学问
比如我们可不可以把边的容量全部加1呢?
有人问:这样最小割不就是不一样了吗?
但是细想一下可以发现:其实在加1的情况下,原来的最小割确实变了,但是增大了多少就等于最少要删去的边数
因为对于每条边,容量又多了一个1,在最小割的前提下,肯定是删去越少的边数的情况更优
举个栗子:
强迫症,这图画了我半天
Code:
#include<bits/stdc++.h>
#define INF 0x7f7f7f7f
#define M 1010
#define N 50
using namespace std;
struct node{
int to,cap;
int nxt;
node(int a,int b):to(a),cap(b){ }
node(){ }
}b[M<<1];
int head[N],deep[N];
int n,m,S,T,t=1,Maxflow,Ans;
int read()
{
int s=0;
char c=getchar();
while(!isdigit(c))
c=getchar();
while(isdigit(c))
{
s=(s<<1)+(s<<3)+c-'0';
c=getchar();
}
return s;
}
void add(int x,int y,int cap)
{
b[++t]=node(y,cap);
b[t].nxt=head[x];
head[x]=t;
b[++t]=node(x,0);
b[t].nxt=head[y];
head[y]=t;
return;
}
bool BFS()
{
int i,cur;
int to,cap;
queue<int>p;
memset(deep,0,sizeof(deep));
deep[S]=1;p.push(S);
while(!p.empty())
{
cur=p.front();p.pop();
for(i=head[cur];i;i=b[i].nxt)
{
to=b[i].to;cap=b[i].cap;
if(cap&&!deep[to])
{
deep[to]=deep[cur]+1;
p.push(to);
if(to==T)
return 1;
}
}
}
return 0;
}
int Dinic(int k,int flow)
{
if(k==T)
return flow;
int i,to,cap,res,rest=flow;
for(i=head[k];i&&rest;i=b[i].nxt)
{
to=b[i].to;cap=b[i].cap;
if(cap&&deep[to]==deep[k]+1)
{
res=Dinic(to,min(rest,cap));
if(!res)
deep[to]=0;
b[i].cap-=res;
b[i^1].cap+=res;
rest-=res;
}
}
return flow-rest;
}
int main()
{
int i,flow;
int x,y,cap;
n=read();m=read();
S=1;T=n;
for(i=1;i<=m;i++)
{
x=read();y=read();cap=read();
add(x,y,cap);
}
while(BFS())//先求最小割
while((flow=Dinic(S,INF)))
Maxflow+=flow;
while(BFS())
while((flow=Dinic(S,INF)))
Maxflow+=flow;
for(i=2;i<=t;i+=2)//改变边
b[i].cap+=b[i^1].cap+1,b[i^1].cap=0;//初始正边并1,反边还是赋0
while(BFS())//再跑一次
while((flow=Dinic(S,INF)))
Ans+=flow;
printf("%d %d",Maxflow,Ans-Maxflow);//一次性输出
return 0;
}