您的位置:首页 > 理论基础 > 计算机网络

acdreamoj 1211 有上下界的网络流

2016-04-14 10:33 661 查看
这是一道有下届的网络流的题目,刚开始不是很会搞,学了一段时间,其实就是新建立一个源点S和汇点T,然后每条边(u,v),容量是c,最低下限是b,连S 到v和u到T的容量为b的边,之后再连接u到v的容量为c-b的边,最后求的是各边流量,跑一遍最大流,如果等于最低下限和,那么就有可行流

#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
const int oo=1e9;
const int mm=800005;
const int mn=205;
int node,src,dest,edge;
int ver[mm],flow[mm],next[mm];
int head[mn],work[mn],dis[mn],q[mn];
void prepare(int _node,int _src,int _dest)
{
node=_node,src=_src,dest=_dest;
for(int i=0;i<node;++i)
head[i]=-1;
edge=0;
}
void addedge(int u,int v,int c)
{
ver[edge]=v,flow[edge]=c,next[edge]=head[u],head[u]=edge++;
ver[edge]=u,flow[edge]=0,next[edge]=head[v],head[v]=edge++;

}
bool Dicnic_bfs()
{
int i,u,v,l,r=0;
for(i=0;i<node;++i)
dis[i]=-1;
dis[q[r++]=src]=0;
for(l=0;l<r;++l)
for(i=head[u=q[l]];i>=0;i=next[i])
if(flow[i]&&dis[v=ver[i]]<0)
{
dis[q[r++]=v]=dis[u]+1;
if(v==dest)
return 1;
}
return 0;
}
int Dicnic_dfs(int u,int exp)
{
if(u==dest)
return exp;
for(int &i=work[u],v,tmp;i>=0;i=next[i])
if(flow[i]&&dis[v=ver[i]]==dis[u]+1&&(tmp=Dicnic_dfs(v,min(exp,flow[i])))>0)
{
flow[i]-=tmp;
flow[i^1]+=tmp;
return tmp;
}
return 0;
}
int Dicnic_flow()
{
int i,ret=0,delta;
while(Dicnic_bfs())
{
for(i=0;i<node;++i)
work[i]=head[i];
while(delta=Dicnic_dfs(src,oo))
ret+=delta;
}
return ret;
}
int n,m;
vector<int> _edge,_low;
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
int flow2=0;
prepare(n+2,0,n+1);
_edge.clear();
_low.clear();
for(int i=0; i<m; i++)
{
int u,v,low,high;
scanf("%d%d%d%d",&u,&v,&low,&high);
flow2+=low;
addedge(0,v,low);
addedge(u,n+1,low);
_edge.push_back(edge);
_low.push_back(low);//这两句一定要在加u到v的前面,控制边数
addedge(u,v,high-low);
}
int flow1=Dicnic_flow();
if(flow1!=flow2)
printf("NO\n");
else
{
printf("YES\n");
int _size=_edge.size();
for(int i=0;i<_size;i++)
{
printf("%d\n",flow[_edge[i]^1]+_low[i]);
//因为flow是从0开始的,而edge是两条两条加的,而且直接跳到了++后,所以当edge是4的时候flow对应的正好是3,然后加2才正好是flow的5,这是edge+1正好对应上
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  图论 网络流