题面
题意就是有N个点的图,边有费用,点和边的容量都是1 ,问源到汇的最大流及最小费用。就是果的最小费用最大流。
这里用连续最短路算法。不断用SPFA寻找增广路,并沿着其增广。点有容量就把它拆成入点与出点,入点向出点连一条边限制这个点的容量。
做这题是因为我在##之星的比赛中,看到费用流就有点慌,直接复制以前的程序,现在就当复习一下代码吧。
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))
typedef long long LL;
const int N=440,nn=402,M=400020,oo=1e9;
int head[N],to[M],nex[M],cost[M],cap[M],cnt=2;
int q[N],id[N],pre[N],d[N],flow[N];
bool vis[N];
int n,m,days,len;
void add(int u,int v,int ca,int co)
{
to[cnt]=v;
nex[cnt]=head[u];
cap[cnt]=ca;
cost[cnt]=co;
head[u]=cnt++;
to[cnt]=u;
nex[cnt]=head[v];
cap[cnt]=0;
cost[cnt]=-co;
head[v]=cnt++;
}
bool spfa(int s,int t)
{
for(int i=0;i<N;i++)
d[i]=oo;
d[s]=0;
flow[s]=oo;
int hh=0,tt=0;
q[0]=s;
while(hh<=tt)
{
int hy=q[hh%nn];
vis[hy]=false;
hh++;
for(int h=head[hy];h;h=nex[h])
if(cap[h]&&d[to[h]]>d[hy]+cost[h])
{
d[to[h]]=d[hy]+cost[h];
pre[to[h]]=hy;
id[to[h]]=h;
flow[to[h]]=min(flow[hy],cap[h]);
if(!vis[to[h]])
{
vis[to[h]]=1;
tt++;
q[tt%nn]=to[h];
if(d[to[h]]<d[q[hh%nn]])
swap(q[tt%nn],q[hh%nn]);
}
}
}
return d[t]!=oo;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
add(i,i+200,1,0);
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u+200,v,1,w);
}
while(spfa(201,n))
{
days+=flow[n];
len+=flow[n]*d[n];
for(int i=n;i!=201;i=pre[i])
{
cap[id[i]]-=flow[n];
cap[id[i]^1]+=flow[n];
}
}
cout<<days<<" "<<len<<endl;
return 0;
}