Solution - P2469 [SDOI2010] 星际竞速

一个不同以往的浪漫做法。(

和主流做法有很大不同。


容易将题目转化为最小费用路径覆盖。

我们联想最小路径覆盖怎么做,是建图跑最大匹配然后 \(n - \mathrm{maxflow}\)。正确是因为 \(\mathrm{maxflow}\) 可以表示删去的路径数量。

这里我们使用类似的做法。我们将边权赋为 \(w-a_v\),表示需要花费 \(w\) 的时间,但是可以省去传送带来的 \(a_v\)。然后跑最小费用流即可。答案为 \(\Sigma a - \mathrm{mincost}\)

#include <bits/stdc++.h>
#define llong long long
#define N 2003
#define M 20004
using namespace std;

#define bs (1<<20)
char buf[bs], *p1, *p2;
#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,bs,stdin),p1==p2)?EOF:*p1++)
template<typename T>
inline void read(T& x){
	x = 0; int w = 1;
	char ch = gc();
	while(ch < '0' || ch > '9'){
		if(ch == '-') w = -w;
		ch = gc();
	}
	while(ch >= '0' && ch <= '9')
		x = (x<<3)+(x<<1)+(ch^48), ch = gc();
	x *= w;
}
template<typename T, typename ...Args>
inline void read(T& x, Args& ...y){
	return read(x), read(y...);
}

int n, m, s;
int a[N];

int to[M<<1], siz[M<<1], val[M<<1], nxt[M<<1], head[N], gsiz = 1;
#define mkarc(u,v,w1,w2) (++gsiz, to[gsiz]=v, siz[gsiz]=w1, val[gsiz]=w2, nxt[gsiz]=head[u], head[u]=gsiz)
int dis[N], vis[N], cur[N];

int que[N*N], he, ta;
inline bool spfa(){
	for(int i = 1; i <= n*2+2; ++i) 
		dis[i] = 1e9+7, vis[i] = 0, cur[i] = head[i];
	vis[que[he = ta = 1] = 1] = true, dis[1] = 0;
	while(he <= ta){
		int u = que[he++]; vis[u] = false;
		for(int i = head[u]; i; i = nxt[i]){
			int v = to[i];
			if(siz[i] && dis[u]+val[i] < dis[v]){
				dis[v] = dis[u]+val[i];
				if(!vis[v]) vis[que[++ta] = v] = true;
			}
		}
	}
	while(he <= ta) vis[que[he++]] = false;
	return (dis[2] <= 1e9);
}
inline int dfs(int u, int f, int& cost){
	if(u == 2) return f;
	int res = 0; vis[u] = true;
	for(int &i = cur[u]; i; i = nxt[i]){
		int v = to[i];
		if(!siz[i] || dis[v] != dis[u]+val[i] || vis[v]) continue;
		int d = dfs(v, min(f, siz[i]), cost);
		if(!d) dis[v] = 1e9+7;
		siz[i] -= d, f -= d;
		siz[i^1] += d, res += d;
		cost += val[i]*d;
		if(!f) break;
	}
	vis[u] = false;
	return res;
}
inline int dinic(int& cost){
	int res = 0;
	while(spfa() && dis[2] < 0) dfs(1, 1e9+7, cost);
	return res;
}

int main(){
	freopen("in.txt", "r", stdin);
	read(n, m);
	for(int i = 1; i <= n; ++i) read(a[i]), s += a[i];
	for(int i = 1; i <= m; ++i){
		int u, v, w;
		read(u, v, w);
		if(u > v) swap(u, v);
		w -= a[v];
		mkarc(u+2, v+n+2, 1, w), mkarc(v+n+2, u+2, 0, -w);
	}
	for(int i = 1; i <= n; ++i){
		mkarc(1, i+2, 1, 0), mkarc(i+2, 1, 0, 0);
		mkarc(i+n+2, 2, 1, 0), mkarc(2, i+n+2, 0, 0);
	}
	int c = 0;
	dinic(c);
	printf("%d", s+c);
	return 0;
}

posted @ 2026-02-26 11:03  Hootime  阅读(1)  评论(0)    收藏  举报