链接
https://www.luogu.org/problemnew/show/P2153
大意
有一张有向图,有 条边,在只希望每条边只走一次的情况下,使经过路径长度的和最小
思路
用网络流来处理每条边只走一次的要求,既然要求只走一次,那么它的容量即为1,我们把 点拆成两个点入点和出点,他们之间的容量为1,代价为0,而在有路的两个点间再建边,容量为1,代价为这条路的长度,然后把源点和起点相连,容量为无穷大,终点和汇点相连,容量也是无穷大,再跑一遍最小费用最大流即为答案
代码
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#define N 5001
#define M 50001
using namespace std;int f,n,m,s,t,ans1,ans2,u,v,w,g;char c;
int read()
{
f=0;
while(c=getchar(),c<=47||c>=58);f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),c>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
return f;
}
struct node{int next,to,w,g;}e[M<<1];
int dis[N],l[N],tot,pos[N];
bool vis[N];
void add(int u,int v,int w,int c)
{
e[tot]={l[u],v,w,c};l[u]=tot++;
e[tot]={l[v],u,0,-c};l[v]=tot++;
return;
}
bool spfa()
{
fill(dis+1,dis+1+t,50234567);
memset(vis,0,sizeof(vis));
queue<int>q;q.push(s);dis[s]=0;vis[s]=true;
while(q.size())
{
int x=q.front();q.pop();vis[x]=true;
for(int i=l[x];~i;i=e[i].next)
{
int y=e[i].to,w=e[i].g;
if(e[i].w&&dis[y]>dis[x]+w)
{
dis[y]=dis[x]+w;
pos[y]=i;
if(!vis[y]) q.push(y),vis[y]=true;
}
}
vis[x]=false;
}
return dis[t]<50234567;
}
void updata()
{
int x=t;
while(x!=s)
{
int i=pos[x];
e[i].w--;
e[i^1].w++;
x=e[i^1].to;
}
ans1++;
ans2+=dis[t];
return;
}
void EK()
{
while(spfa())
updata();return;
}
int main()
{
memset(l,-1,sizeof(l));
n=read();m=read();s=1;t=n+n;
add(s,n+1,1e9,0);add(n,t,1e9,0);//终点和起点与源点和汇点相连
for(int i=2;i<n;i++) add(i,i+n,1,0);//中间的入点和出点相连
for(int i=1,u,v,c;i<=m;i++)
{
u=read();v=read();c=read();
add(u+n,v,1,c);//u的出点与v的入点相连
}
EK();
printf("%d %d",ans1,ans2);//输出
}