最小路径覆盖问题
每个星球必须恰好去一次,而每次高速航行都是从一个星球到另一个星球。
那么高速航行的起点可以保证被去过
高速航行和空间跳跃可以是互相独立的
将每个点$i$拆成$i_1,i_2$,套路地连边
$link(S,i_1,1,0)$
$link(S,i_2,1,val_i)$
$link(i_2,T,1,0)$
对于每条边$(u,v,w)$:
$link(u_1,v_2,w)$
蓝后跑一遍费用流,费用流会覆盖所有路径$(i_2,T)$
满流的最小代价即为答案
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define N 2005
#define M 100005
int n,m,S,T,d[N],a[N],p[N],tC;
queue <int> h; bool inh[N];
int cnt=,hd[N],nxt[M],ed[N],poi[M],val[M],cst[M];
inline void adde(int x,int y,int v1,int v2){
nxt[ed[x]]=++cnt, hd[x]=hd[x]?hd[x]:cnt,
ed[x]=cnt, poi[cnt]=y, val[cnt]=v1,cst[cnt]=v2;
}
inline void link(int x,int y,int v1,int v2){adde(x,y,v1,v2),adde(y,x,,-v2);}
bool bfs(){
memset(d,,sizeof(d)); int inf=d[];
h.push(S); d[S]=; a[S]=inf; inh[S]=;
while(!h.empty()){
int x=h.front(); h.pop(); inh[x]=;
for(int i=hd[x];i;i=nxt[i]){
int to=poi[i];
if(val[i]>&&d[to]>d[x]+cst[i]){
d[to]=d[x]+cst[i]; p[to]=i;
a[to]=min(a[x],val[i]);
if(!inh[to]) inh[to]=,h.push(to);
}
}
}if(d[T]==inf) return ;
tC+=a[T]*d[T];
for(int i=T;i!=S;i=poi[p[i]^])
val[p[i]]-=a[T],val[p[i]^]+=a[T];
return ;
}
int main(){
scanf("%d%d",&n,&m); int u,v,w;
S=n*+; T=S+;
for(int i=;i<=n;++i){
link(S,i,,);
link(i+n,T,,);
scanf("%d",&w);
link(S,i+n,,w);
}
for(int i=;i<=m;++i){
scanf("%d%d%d",&u,&v,&w);
if(u>v) swap(u,v);
link(u,v+n,,w);
}while(bfs());
printf("%d",tC);
return ;
}