传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1927
思路:拆点拆成x和x'
S向x'连边,容量为1,费用为定位时间
S向x连边,容量为1,费用为0
对于原图的边u->v
u向v‘连边,容量为1,费用为时间
x’向T连边,容量为1,费用为0;
跑一遍费用流即可
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int maxn=1610,maxm=200010;
using namespace std;
int n,m,A[maxn],pre[maxm],now[maxn],son[maxm],val[maxm],cost[maxm],from[maxm],tot=1;
int S=maxn-2,T=maxn-1,dis[maxn],q[maxm+10],head,tail,last[maxn],minc,flow;
bool bo[maxn];
struct Edge{int x,y,z;}E[maxm];
void add(int a,int b,int c,int d){pre[++tot]=now[a],now[a]=tot,from[tot]=a,son[tot]=b,val[tot]=c,cost[tot]=d;}
void ins(int a,int b,int c,int d){add(a,b,c,d),add(b,a,0,-d);}
int p0(int x){return x<<1;}
int p1(int x){return (x<<1)|1;}
bool spfa(){
memset(dis,63,sizeof(dis));int inf=dis[0];
memset(bo,0,sizeof(bo));
q[tail=1]=S,dis[S]=head=0;
while (head!=tail){
if (++head>maxm) head=1;
int x=q[head];
for (int y=now[x];y;y=pre[y])
if (val[y]>0&&dis[son[y]]>dis[x]+cost[y]){
dis[son[y]]=dis[x]+cost[y],last[son[y]]=y;
if (!bo[son[y]]){
if (++tail>maxm) tail=1;
q[tail]=son[y],bo[son[y]]=1;
}
}
bo[x]=0;
}
return dis[T]<inf;
}
void find(){
int lim=1e9;
for (int x=T,y;x!=S;x=from[y]) y=last[x],lim=min(lim,val[y]);
flow+=lim;
for (int x=T,y;x!=S;x=from[y]) y=last[x],minc+=lim*cost[y],val[y]-=lim,val[y^1]+=lim;
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&A[i]);
for (int i=1,x,y,z;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
if (x>y) swap(x,y);
E[i]=(Edge){x,y,z};
}
for (int i=1;i<=n;i++) ins(S,p1(i),1,A[i]),ins(S,p0(i),1,0),ins(p1(i),T,1,0);
for (int i=1;i<=m;i++) ins(p0(E[i].x),p1(E[i].y),1,E[i].z);
while (spfa()) find();
//spfa();
//for (int i=1;i<=n;i++) printf("%d\n",from[last[i]]);
printf("%d\n",minc);
return 0;
}