一道最小费用流裸题
为了防止一个点被选择两次,将一个点拆分为两个点,然后正常建图跑一边最小费用流
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<iostream>
#include<iomanip>
#include<ctime>
#include<algorithm>
#include<cmath>
using namespace std;
int dis[1000];
struct my_road
{
int r,f,v;
}a[100000];
int fir[100000];
int nex[100000];
int dui[1000000];
bool pd[100000];
int fro[100000];
int tot=1;
int s,t;
void add_edge(int l,int r,int f,int v)
{
a[++tot].r=r;
a[tot].f=f;
nex[tot]=fir[l];
fir[l]=tot;
a[tot].v=v;
}
int cost=0;
int add_flow()
{
int u=t;
int flow=2147483647;
while(u!=s)
{
flow=min(flow,a[fro[u]].f);
u=a[fro[u]^1].r;
}
u=t;
while(u!=s)
{
cost+=a[fro[u]].v*flow;
a[fro[u]].f-=flow;
a[fro[u]^1].f+=flow;
u=a[fro[u]^1].r;
}
return flow;
}
bool spfa()
{
int top=1,my_final=2;
memset(dis,0x1f,sizeof(dis));
memset(pd,0,sizeof(pd));
dui[1]=s;
dis[s]=0;
pd[s]=true;
while(top<my_final)
{
int u=dui[top];
for(int o=fir[u];o!=0;o=nex[o])
{
if(a[o].f && dis[a[o].r]>dis[u]+a[o].v)
{
fro[a[o].r]=o;
dis[a[o].r]=dis[u]+a[o].v;
if(!pd[a[o].r]) dui[my_final++]=a[o].r,pd[a[o].r]=true;
}
}
pd[u]=false;
top++;
}
if(dis[t]==0x1f1f1f1f) return false;
return true;
}
int n,m;
inline int getl(int x)
{
if(x==1) return s;
if(x==n) return 2*n;
return x+n;
}
inline int getr(int x)
{
if(x==1) return s;
if(x==n) return 2*n;
return x;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=2;i<n;i++)
{
add_edge(i,i+n,1,0);
add_edge(i+n,i,0,0);
}
s=1;
t=2*n;
for(int i=1;i<=m;i++)
{
int a1,b1,c1;
scanf("%d%d%d",&a1,&b1,&c1);
int l=getl(a1);
int r=getr(b1);
add_edge(l,r,1,c1);
add_edge(r,l,0,-c1);
}
int ans=0;
while(spfa())
{
ans+=add_flow();
}
cout<<ans<<" "<<cost;
return 0;
}