题意
带负环的有上下界最小费用可行流
题解
“有上下界的费用流”:
相当于把这条边拆成流量为下界的边和流量为上界-下界的边,其中第一条是必须流满的。根据最大流的性质,把该边拆成“起点->汇”和“源->中点”,能使这条边尽可能流满。如果还是流不满就输出无解。
“带负环的费用流”:
发现负权边的反向边是正权的。那么就可以把这条负权边拆成流量为上界的边、流量为上界-下界的费用为边权的相反数的反向边,其中第一条是必须流满的。剩下的处理方式同上。
代码
#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);
}