这题用到了最小费用最大流,一条边的容量为1,代价为这条边的长度。
建立超级源点通向节点1,容量为2,代价为0;节点n通向超级汇点,容量为2,代价为0。
之后刷一遍最小费用最大流就行了。
注意:这题里的边都是双向边,比方说从节点x到节点y和从节点y到节点x是不同的走法。
附上AC代码:
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
struct note{
int from,to,w,v,nt;
}side[100010];
queue <int> que;
int n,m,x,y,w,h[1010],dis[1010],f[1010],flow,cost,pre[1010],num,s,t;
bool b[1010];
void add(int x,int y,int w,int v){
side[num]=(note){x,y,w,v,h[x]};
h[x]=num++;
side[num]=(note){y,x,0,-v,h[y]};
h[y]=num++;
}
bool spfa(){
for (int i=0; i<=t; ++i) dis[i]=1e9,b[i]=0;
while (!que.empty()) que.pop();
dis[s]=0,b[s]=1,f[s]=2e9,que.push(s);
while (!que.empty()){
int p=que.front();que.pop(),b[p]=0;
for (int i=h[p]; ~i; i=side[i].nt)
if (side[i].w&&dis[side[i].to]>dis[p]+side[i].v){
dis[side[i].to]=dis[p]+side[i].v;
pre[side[i].to]=i;
f[side[i].to]=min(f[p],side[i].w);
if (!b[side[i].to]){
b[side[i].to]=1;
que.push(side[i].to);
}
}
}
if (dis[t]==1e9) return 0;
flow+=f[t];
cost+=f[t]*dis[t];
for (int i=t; i!=s; i=side[pre[i]].from){
side[pre[i]].w-=f[n];
side[pre[i]^1].w+=f[n];
}
return 1;
}
int main(void){
scanf("%d%d",&n,&m),s=0,t=n+1;
memset(h,-1,sizeof h);
for (int i=1; i<=m; ++i){
scanf("%d%d%d",&x,&y,&w);
add(x,y,1,w),add(y,x,1,w);
}
add(s,1,2,0),add(n,t,2,0);
while (spfa());
printf("%d",cost);
return 0;
}