CodeForces

题目链接

题目大意

  给你n个点,你可以在这个点上建站,也可以通过一条边将这个点与站点(直接/间接)连通。

解题思路

  本题主要是考察建图技巧,因为每个点要么建站,要么与其他点连通,并且至少有一个站点,所以我们再加入一个点,这个点与所有点连通,并且花费是每个点建站的花费,然后再把所有点建一个完全图跑最小生成树就解决问题了。

代码

const int maxn = 2e3+10;
const int maxm = 1e7+10;
int n;
struct INFO {
	int x, y;
} info[maxn];
int c[maxn], k[maxn], tot, p[maxn];
ll g[maxn][maxn], d[maxn];
bool vis[maxn];
ll prim() {
	clr(d, 0x3f);
	d[n+1] = 0;
	int pre;
	for (int i = 1; i<=n; ++i) {
		int u = 0;
		for (int j = 1; j<=n+1; ++j)
			if (!vis[j] && (u==0 || d[j]<d[u])) u = j;
		vis[u] = 1; 
		for (int v = 1; v<=n+1; ++v)
			if (!vis[v] && d[v]>g[u][v]) {
				p[v] = u;
				d[v] = g[u][v];
			} 
	}
	ll sum = 0;
	for (int i = 1; i<=n+1; ++i) sum += d[i];
	return sum;
}
int main(){
	cin >> n;
	for (int i = 1; i<=n; ++i) cin >> info[i].x >> info[i].y;
	for (int i = 1; i<=n; ++i) cin >> c[i];
	for (int i = 1; i<=n; ++i) cin >> k[i];
	for (int i = 1; i<=n; ++i) g[i][n+1] = g[n+1][i] = c[i];
	for (int i = 1; i<=n; ++i)
		for (int j = i+1; j<=n; ++j) {
			ll d = 1LL*(abs(info[i].x-info[j].x)+abs(info[i].y-info[j].y))*(k[i]+k[j]);
			g[i][j] = g[j][i] = d;
		}
	cout << prim() << endl;
	vector<int> ans1;
	vector<P> ans2;
	for (int i = 1; i<=n; ++i) {
		if (p[i]==n+1) ans1.push_back(i);
		else ans2.push_back({p[i], i});
	}
	int sz = ans1.size();
	cout << sz << endl;
	for (int i = 0; i<sz; ++i) printf(i==sz-1 ? "%d
":"%d ", ans1[i]);
	sz = ans2.size();
	cout << sz << endl;
	for (int i = 0; i<sz; ++i) printf("%d %d
", ans2[i].x, ans2[i].y);
	return 0;	
}
原文地址:https://www.cnblogs.com/shuitiangong/p/14399530.html