[SDOI2010] 星际竞速

Description:

给定一个图,每次只能从编号小的节点移动到另一个,代价是边权\(w_i\),或者直接花费\(a_i\)的代价瞬移到\(i\)点,求遍历所有节点的最小代价

Hint:

\(n \le 800\)

Solution:

要求必须经过每一个点,我们就把\(S\)连向\(a'\)容1费\(a_i\),再把\(a'\)连一条容1费0到T

同时我们把每条边\(a->b\)\(a->b'\) 容1费\(w_i\),再把\(S\)连向\(a\)容1费0,跑最小费用最大流就行了

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1 
#define rs p<<1|1
using namespace std;
typedef long long ll;
const int mxn=1e5+5,inf=1e9;
int n,m,k,cnt,hd[mxn];
int S,T,ans,cost,dis[mxn],pre[mxn],bl[mxn],f[mxn],vis[mxn];

inline int read() {
    char c=getchar(); int x=0,f=1;
    while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
    while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
    return x*f;
}
inline void chkmax(int &x,int y) {if(x<y) x=y;}
inline void chkmin(int &x,int y) {if(x>y) x=y;}

struct ed {
    int to,nxt,w,val;
}t[mxn<<1];

inline void add(int u,int v,int w,int z) {
    t[cnt]=(ed) {v,hd[u],w,z}; hd[u]=cnt++;
    t[cnt]=(ed) {u,hd[v],0,-z}; hd[v]=cnt++;
}

int spfa() {
    memset(vis,0,sizeof(vis));
    memset(pre,0,sizeof(pre));
    memset(dis,0x3f,sizeof(dis));
    memset(f,0x3f,sizeof(f));
    queue<int > q; q.push(S);
    dis[S]=pre[S]=0;
    while(!q.empty()) {
        int u=q.front(); q.pop();
        vis[u]=0; 
        for(int i=hd[u];i!=-1;i=t[i].nxt) {
            int v=t[i].to;
            if(t[i].w>0&&dis[v]>dis[u]+t[i].val) {
                dis[v]=dis[u]+t[i].val; pre[v]=u;
                bl[v]=i; f[v]=min(f[u],t[i].w);
                if(!vis[v]) q.push(v),vis[v]=1;
            }
        }
    }
    return pre[T];
}

void Dinic() {
    while(spfa()) {
        ans+=f[T];
        cost+=f[T]*dis[T];
        for(int i=T;i!=S;i=pre[i]) {
            t[bl[i]].w-=f[T];
            t[bl[i]^1].w+=f[T];
        }
    }
}

int get(int x,int y) {
    return (x-1)*n+y;
}

int main()
{
	n=read(); m=read(); T=n*2+1; int u,v,w,x; memset(hd,-1,sizeof(hd));
	for(int i=1;i<=n;++i) x=read(),add(S,i+n,1,x);
	for(int i=1;i<=n;++i) add(i+n,T,1,0),add(S,i,1,0);
	for(int i=1;i<=m;++i) {
		u=read(); v=read(); w=read();
		if(u>v) swap(u,v);
		add(u,v+n,1,w);
	}
    Dinic(); printf("%d",cost);
    return 0;
}

posted @ 2019-03-25 13:09  cloud_9  阅读(82)  评论(0编辑  收藏  举报