zoukankan      html  css  js  c++  java
  • 并不对劲的挑战任务:20162113030

    题意

    带负环的有上下界最小费用可行流

    题解

    “有上下界的费用流”:

    相当于把这条边拆成流量为下界的边和流量为上界-下界的边,其中第一条是必须流满的。根据最大流的性质,把该边拆成“起点->汇”和“源->终点”,能使这条边尽可能流满。如果还是流不满就输出无解。

    “带负环的费用流”:

    发现负权边的反向边是正权的。那么就可以把这条负权边拆成流量为上界的边、流量为上界-下界的费用为边权的相反数的反向边,其中第一条是必须流满的。剩下的处理方式同上。

    代码

    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<queue>
    #include<set>
    #include<stack>
    #include<vector>
    #define rep(i,x,y) for(register int i=(x);i<=(y);++i)
    #define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
    #define view(u,k) for(int k=fir[u];~k;k=nxt[k])
    #define LL long long
    #define maxn 307
    #define maxm 3007
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)&&ch!='-')ch=getchar();
        if(ch=='-')f=-1,ch=getchar();
        while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
        return x*f;
    }
    void write(LL x)
    {
        if(x==0){putchar('0'),putchar('
    ');return;}
        int f=0;char ch[20];
        if(x<0)putchar('-'),x=-x;
        while(x)ch[++f]=x%10+'0',x/=10;
        while(f)putchar(ch[f--]);
        putchar('
    ');
        return;
    }
    int vis[maxn],ss,tt,n,m,fir[maxn],nxt[maxm],v[maxm],fl[maxm],flow,cnte,in[maxn],q[maxn],hd,tl,inq,tim;
    LL dis[maxn],w[maxm],mincost; 
    void ade(int u1,int v1,int fl1,int w1)
    {
    	v[cnte]=v1,nxt[cnte]=fir[u1],fl[cnte]=fl1,w[cnte]=w1,fir[u1]=cnte++;
    	v[cnte]=u1,nxt[cnte]=fir[v1],fl[cnte]=0,w[cnte]=-w1,fir[v1]=cnte++;
    }
    void push(int x){tl++;if(tl==maxn)tl=0;inq++,q[tl]=x;}
    void pop(){hd++;if(hd==maxn)hd=0;inq--;}
    int spfa()
    {
    	rep(i,ss,tt)dis[i]=-1;tim++;hd=1,tl=0;
    	push(tt),dis[tt]=0,vis[tt]=tim;
    	while(inq)
    	{
    		int u=q[hd];pop();
    		view(u,k)if(fl[k^1]&&(dis[v[k]]==-1||dis[v[k]]>dis[u]+w[k^1])){dis[v[k]]=dis[u]+w[k^1];if(tim!=vis[v[k]])push(v[k]);}
    		vis[u]=0;
    	}
    	return dis[ss]!=-1;
    }
    int getfl(int u,int nowfl)
    {
    	if(u==tt||!nowfl)return nowfl;
    	if(vis[u]==tim)return 0;vis[u]=tim;
    	int sum=0,tmp=0;
    	view(u,k)
    	{
    		if(!nowfl)break;
    		if(fl[k]&&dis[v[k]]==dis[u]-w[k]&&(tmp=getfl(v[k],min(nowfl,fl[k])))>0)
    		{sum+=tmp,mincost+=w[k]*((LL)tmp),nowfl-=tmp,fl[k]-=tmp,fl[k^1]+=tmp;}
    	}vis[u]=0;
    	return sum;
    }
    int main()
    {
        n=read(),m=read(),ss=0,tt=n+1;
        rep(i,ss,tt)fir[i]=-1;
    	rep(i,1,m)
        {
        	int x=read(),y=read(),lw=read(),up=read(),c=read();
        	if(c>=0){ade(x,y,up-lw,c),mincost+=(LL)lw*c,in[x]-=lw,in[y]+=lw;}
        	else {ade(y,x,up-lw,-c),mincost+=(LL)up*c,in[x]-=up,in[y]+=up;}
    	}
    	rep(i,1,n)
    	{
    		if(in[i]>0)flow+=in[i],ade(ss,i,in[i],0);
    		if(in[i]<0)ade(i,tt,-in[i],0);
    	}
    	while(spfa()){tim++;flow-=getfl(ss,0x7fffffff);}
    	if(flow)puts("QAQ");
    	else write(mincost);
    	return (0^0);
    }
    
  • 相关阅读:
    BIEE建模参考规范
    informatica 学习日记整理
    Web Service 的工作原理
    Oracle 时间差计算
    oracle基础知识
    Oracle 外连接和 (+)号的用法
    根据appId匹配项目名称
    vue技术分享-你可能不知道的7个秘密
    echarts3 迁徙图 迁入迁出
    ES6学习笔记
  • 原文地址:https://www.cnblogs.com/xzyf/p/12047829.html
Copyright © 2011-2022 走看看