[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;
}

  1. DAG的最小路径覆盖相关 请见我的洛谷博客 ↩︎

posted @ 2018-12-24 13:57  nosta  阅读(302)  评论(0编辑  收藏  举报