题目要求算出通过增加边的容量能够使得最大流增加的边数
思路:先用Dinic算出图的最大流,然后用DFS分别从始点和汇点进行搜索标记,最后枚举算出有多少点可以改变最大流即可
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=501;
const int maxm=200000;
const int inf=1<<29;
int n,m,e,st,des,head[maxn],pnt[maxm],nxt[maxm],cost[maxm],level[maxn],q[maxn];
bool visa[maxn],visb[maxn];
void AddEdge(int u,int v,int c)
{
pnt[e]=v;nxt[e]=head[u];cost[e]=c;head[u]=e++;
pnt[e]=u;nxt[e]=head[v];cost[e]=0;head[v]=e++;
}
bool BFS()
{
memset(level,0,sizeof(level));
int pre=0,last=1;
q[pre]=st;
level[st]=1;
while(pre<last)
{
if(q[pre]==des)
return true;
for(int i=head[q[pre]];i!=-1;i=nxt[i])
if(cost[i]&&!level[pnt[i]])
{
level[pnt[i]]=level[q[pre]]+1;
q[last++]=pnt[i];
}
pre++;
}
return false;
}
int DFS(int u,int sum)
{
if(u==des)
return sum;
for(int i=head[u],t;i!=-1;i=nxt[i])
if(cost[i]&&level[pnt[i]]==level[u]+1&&(t=DFS(pnt[i],min(sum,cost[i]))))
{
cost[i]-=t;
cost[i^1]+=t;
return t;
}
return level[u]=0;
}
void DFSA(int u)
{
visa[u]=1;
for(int i=head[u];i!=-1;i=nxt[i])
if(!visa[pnt[i]]&&cost[i])
DFSA(pnt[i]);
}
void DFSB(int u)
{
visb[u]=1;
for(int i=head[u];i!=-1;i=nxt[i])
if(!visb[pnt[i]]&&cost[i^1])
DFSB(pnt[i]);
}
void Dinic()
{
while(BFS())
while(1)
{
int val=DFS(st,inf);
if(!val)
break;
}
memset(visa,0,sizeof(visa));
memset(visb,0,sizeof(visb));
DFSA(st);
DFSB(des);
int ans=0;
for(int i=0;i<e;i+=2)
{
if(!cost[i]&&visa[pnt[i^1]]&&visb[pnt[i]])
ans++;
}
printf("%d\n",ans);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
st=e=0,des=n-1;
memset(head,-1,sizeof(head));
for(int i=0;i<m;i++)
{
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
AddEdge(u,v,c);
}
Dinic();
}
return 0;
}