题目:
题解:
最小费用最大流裸题,拆点xi,yi,建立源点汇点,向1和n连边容量INF
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#define INF 1e9
#define N 40000
using namespace std;
int nxt[N*2+5],point[N*2+5],v[N*2+5],remind[N*2+5],cost[N*2+5],tot=-1,last[N*2+5];
int maxflow,mincost,dis[N*2+5],n,m;
bool vis[N*2+5];
void addline(int x,int y,int cap,int value)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; remind[tot]=cap; cost[tot]=value;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; remind[tot]=0; cost[tot]=-value;
}
int addflow(int s,int t)
{
int now=t,ans=INF;
while (now!=s)
{
ans=min(ans,remind[last[now]]);
now=v[last[now]^1];
}
now=t;
while (now!=s)
{
remind[last[now]]-=ans;
remind[last[now]^1]+=ans;
now=v[last[now]^1];
}
return ans;
}
bool bfs(int s,int t)
{
queue<int>q;
q.push(s);
memset(dis,0x7f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s]=0;vis[s]=true;
while (!q.empty())
{
int now=q.front(); q.pop();
vis[now]=false;
for (int i=point[now];i!=-1;i=nxt[i])
if (dis[v[i]]>dis[now]+cost[i] && remind[i])
{
dis[v[i]]=dis[now]+cost[i];
last[v[i]]=i;
if (!vis[v[i]])
{
vis[v[i]]=true;
q.push(v[i]);
}
}
}
if (dis[t]>INF) return false;
int flow=addflow(s,t);
maxflow+=flow;
mincost+=flow*dis[t];
return true;
}
void majoy(int s,int t){while(bfs(s,t));}
int main()
{
memset(point,-1,sizeof(point));
memset(nxt,-1,sizeof(nxt));
int i,a,b,c;
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
addline(a,b+n,1,c);
}
addline(0,1,INF,0);
addline(n*2,n*2+1,INF,0);
for (i=1;i<=n;i++)
addline(i+n,i,1,0);
majoy(0,n*2+1);
printf("%d %d",maxflow,mincost);
}