POJ-3204-Ikki's Story I - Road Reconstruction

本文介绍了一种解决最大流问题的方法——Dinic算法,并提供了详细的C++实现代码。文章通过具体实例展示了如何利用Dinic算法计算图的最大流,并通过DFS搜索确定哪些边的容量增加可以进一步提高最大流。

题目要求算出通过增加边的容量能够使得最大流增加的边数

思路:先用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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值