[SDOI2010] 星际竞速
给定有向无环图G(V,E),以及定位时间A[N],要求定位到某个星体再经过每个点恰好一次的最少时间。
带权最小不相交路径覆盖 与最小不相交路径覆盖相似[1]。
初态下总花费sum a[i]
现设想从 x走到y,那么总花费的变化量为 v(x,y)-a[y].
进一步可发现,每连接一条x到y的边,总费用增加v(x,y);一个点y存在一个走入的决策,那么总费用就会减小a[y]
像这样建图跑MC(区别于MFMC)即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N=1e5+10;
const int M=1e6+10;
const int inf=0x3f3f3f3f;
int S=N-1,T=N-2;
int head[N],to[M],upp[M],len[M],last[M],cnt=1;
int que[M],dis[N],flo[N],pre[N],hd,tl;
bool inq[N];
void add_edge(int x,int y,int u,int w) {
to[++cnt]=y,upp[cnt]=u,len[cnt]= w,last[cnt]=head[x],head[x]=cnt;
to[++cnt]=x,upp[cnt]=0,len[cnt]=-w,last[cnt]=head[y],head[y]=cnt;
}
bool spfa() {
memset(dis,inf,sizeof dis);
dis[S]=0,inq[S]=1,flo[S]=inf;
que[hd=0,tl=1]=S;
while(hd<tl) {
int x=que[++hd];
for(int i=head[x]; i; i=last[i]) if(upp[i] && dis[to[i]]>dis[x]+len[i]) {
dis[to[i]]=dis[x]+len[i];
pre[to[i]]=i;
flo[to[i]]=min(flo[x],upp[i]);
if(!inq[to[i]]) inq[to[i]]=1, que[++tl]=to[i];
}
inq[x]=0;
}
return dis[T]!=inf;
}
inline long long arg() {
for(int x=T; x && x!=S; x=to[pre[x]^1])
upp[pre[x]]-=flo[T], upp[pre[x]^1]+=flo[T];
return 1LL*flo[T]*dis[T];
}
int n,m,a[N];
long long ans;
int main() {
scanf("%d%d",&n,&m);
for(int i=1; i<=n; ++i) {
scanf("%d",a+i);
ans+=a[i];
add_edge(S,i,1,0);
add_edge(i+n,T,1,-a[i]);
}
for(int x,y,w,i=m; i--; ) {
scanf("%d%d%d",&x,&y,&w);
if(x>y) swap(x,y);
add_edge(x,y+n,1,w);
}
while(spfa() && dis[T]<0) ans+=arg();
printf("%lld\n",ans);
return 0;
}