据说这是最小路径覆盖问题??反正我这么弱是不知道。
实际上,由于边是有方向的,所以如果对于任意一个点,只要入度=1,出度=1,就一定能保证满足题意。那么,我们只需要让每个点保证它去向的点只有1个,然后考虑它的前驱即可。
那么,如果令x表示该点是出发向其它的,x'表示到达的,则构图如下:
1.瞬移:从S->x',流量为1,费用为瞬移的花费;
2.航道x->y:从x->y',流量为1,费用为航道花费;
3.显然任意x必须要有流量才能出发,且只能出发去一个地方,故:S->x,流量为1,费用为0;
4.显然任意x'的入度为1,但上述条件无法保证,古:x'->T,流量为1,费用为0;
这样任意最大流都是一个合法的方案,最有解即最小费用最大流。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 60005
#define inf 1000000000
using namespace std;
int n,m,tot=1,sta,ans,gol,fst[N],pnt[N],len[N],cst[N],nxt[N],d[N],e[N],h[N]; bool vis[N];
void add(int aa,int bb,int cc,int dd){
pnt[++tot]=bb; len[tot]=cc; cst[tot]=dd; nxt[tot]=fst[aa]; fst[aa]=tot;
}
bool spfa(){
memset(vis,0,sizeof(vis)); int i;
for (i=sta; i<=gol; i++) d[i]=inf; d[sta]=0;
int head=0,tail=1; h[1]=sta;
while (head<tail){
head=head%(N-5)+1; int x=h[head],p; vis[x]=0;
for (p=fst[x]; p; p=nxt[p]) if (len[p]){
int y=pnt[p];
if (d[x]+cst[p]<d[y]){
d[y]=d[x]+cst[p]; if (vis[y]) continue;
vis[y]=0; tail=tail%(N-5)+1; h[tail]=y; e[y]=p;
}
}
}
return d[gol]<inf;
}
void updata(){
int i,tmp=inf;
for (i=gol; i!=sta; i=pnt[e[i]^1]) tmp=min(tmp,len[e[i]]);
ans+=tmp*d[gol];
for (i=gol; i!=sta; i=pnt[e[i]^1]){
len[e[i]]-=tmp; len[e[i]^1]+=tmp;
}
}
int main(){
scanf("%d%d",&n,&m); int i;
sta=0; gol=n<<1|1;
for (i=1; i<=n; i++){
int x; scanf("%d",&x); add(0,i+n,1,x); add(i+n,0,0,-x);
add(0,i,1,0); add(i,0,0,0); add(i+n,gol,1,0); add(gol,i+n,0,0);
}
for (i=1; i<=m; i++){
int x,y,z; scanf("%d%d%d",&x,&y,&z);
if (x>y) swap(x,y); add(x,y+n,1,z); add(y+n,x,0,-z);
}
while (spfa()) updata(); printf("%d\n",ans);
return 0;
}
by lych
2016.2.3