并不对劲的挑战任务: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('\n');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('\n');
    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);
}

猜你喜欢

转载自www.cnblogs.com/xzyf/p/12047829.html