zoj 2314 Reactor Cooling--无源汇有上下界最大流--递归sap

/*
	我也没有读题  刚学就直接搜的这类题    找了个简单的练习
	大致上好像是这么个意思   给你一个图   边有上下界
	求无源汇最大流   没有输出NO  有则输出 YES 并输出  各边的流量
*/
#include<iostream>
#include<string.h>
using namespace std;
const int N=205;
struct node
{
	int u,v;
}e[N*N];
int l[N][N],u[N][N],g[N][N],d[N],num[N],n,m,sink,src;
int min(int a,int b){return a<b?a:b;}
int sap(int u,int f)
{
	if(u==sink)  
        return f;  
    int v,mind=n+1,last=f,cost;
    for(v=0;v<=n+1;++v)  
    {  
        if(g[u][v]>0)//有流量  
        {  
            if(d[u]==d[v]+1)//有允许边  
            {  
                cost=sap(v,min(last,g[u][v]));  
                g[u][v]-=cost;//修改图  
                g[v][u]+=cost;  
                last-=cost;//修改剩余流量  
  
                if(d[src]>=n+2)//结束标志  
                    return f-last;  
  
                if(last==0)//使用完就退出  
                    break;  
            }  
            if(d[v]<mind)//下面更新距离的时候用  求其能连接到的最小距离   这个判断和上边的那个判断并列  因为他们是互斥的,只有当找不到允许边的时候才用得着mind  
                mind=d[v];  
        }  
    }  
  
    if(last==f)//流量没有使用  即  没有允许边  
    {  
        --num[d[u]];  
        if(num[d[u]]==0)//若出现断层  
        {  
            d[src]=n+2;  
        }  
        d[u]=mind+1;  
        ++num[d[u]];  
    }  
    return f-last;  
}
int main()
{
	int t,i,j,a,b,c,h;
	cin>>t;
	while(t--)
	{
		memset(g,0,sizeof(g));
		memset(l,0,sizeof(l));//曾经忘了初始化这俩   老是错 
		memset(u,0,sizeof(u));//
		cin>>n>>m;
		sink=n+1;
		src=0;
		for(i=1;i<=m;++i)
		{
			cin>>a>>b>>c>>h;
			e[i].u=a;//记录边   以便   存在答案是输出用
			e[i].v=b;
			l[a][b]=c;
			u[a][b]=h;
		}
		b=0;
		for(i=1;i<=n;++i)
		{
			a=0;
			for(j=1;j<=n;++j)
			{
				a+=l[j][i]-l[i][j];//统计  输入流比输出流多多少   
				g[i][j]=u[i][j]-l[i][j];
			}
			if(a>0)
				b+=g[0][i]=a;
			else g[i][n+1]=-a;
		}
		c=0;
		memset(d,0,sizeof(d));
		memset(num,0,sizeof(num));
		for(num[0]=n+2;d[0]<n+2;)
			c+=sap(0,0x7fffffff);
		if(c<b)
			cout<<"NO"<<endl;
		else
		{
			cout<<"YES"<<endl;
			for(i=1;i<=m;++i)
				cout<<(u[e[i].u][e[i].v]-g[e[i].u][e[i].v])<<endl;
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值