D. Shichikuji and Power Grid(最小生成树 + 超级源点)

文章描述了一个关于在n个城市中建立电力供应的问题,要求通过建造发电站或连接已有电力的城市来实现,同时成本最低。解决方案是使用最小生成树算法,考虑在每个城市建立发电站的成本和城市间连接的费用。给出的代码示例展示了如何构建和排序边,以找到最优的发电站位置和连接组合。
摘要由CSDN通过智能技术生成

Problem - D - Codeforces

七石二是南黑蜗牛寺的新住寺神。她的第一份工作是:在x县有n个新城市,城市编号从1到n。城市i位于神社以北1公里,神社以东y公里。(æi, yi) = (æj, Vj)是可能的,即使i # j。七石市必须为每个城市提供电力,方法是在每个城市建立一个发电站,或者在这个城市和另一个已有电力的城市之间建立连接。所以,如果一个城市有发电站,或者它通过直接连接或通过连接链连接到一个有电的城市,这个城市就有电。在城市i建造一个发电站将花费c日元;在i市和j市之间进行连接将花费k + k日元每公里用于连接的电线。然而,导线只能向基本方向(北、南、东、西)移动。电线可以互相交叉。每根导线的两端都必须位于某些城市。如果用一根导线连接城市i和城市j,导线将通过从城市i到城市j的任何最短路径。因此,如果连接城市耶内和城市j,导线的长度为æ æjl + lyi - yl km。Shichikuji想尽可能少花钱做这份工作,因为在她看来,世界上除了钱就没有其他东西了。然而,她在五年级的时候就去世了,所以她不够聪明。因此,新的常驻神需要你的帮助。因此,你必须向七城提供以下信息:向所有城市提供电力所需的最低日元金额,将在哪些城市建造发电站,以及将建立的连接。如果有多种方式选择城市和连接,以获得最低价的建设,然后打印其中任何一个。输入第一行输入包含一个整数n(1≤n≤2000)——城市数量。然后,有n行。第i行包含两个用空格分隔的整数x;(1 <x < 10°)和y;(1 < y;< 10) -第i个城市的坐标。下一行包含n个用空格分隔的整数c1, C2,..,Cn (1 < c < 10°)-在第i个城市建造一座发电站的费用。最后一行包含n个用空格分隔的整数k1, k2, .., kn (1 < ki≤10°)。

输出在第一行打印一个整数,表示所需日元的最小金额。然后,打印一个整数v-要建造的发电站的数量。接下来,打印v个用空格分隔的整数,表示将要建造电站的城市的指数。每个数字应该在1到n之间,并且所有数字都应该是成对不同的。你可以按任意顺序打印这些数字。在此之后,打印一个整数e-要建立的连接数。最后,打印e对整数a和b (1 < a,b≤n, a b),表示将建立城市a和城市b之间的连接。每个无序城市对最多应该被包含一次(对于每个(a, b)不应该有更多的(a, b)或(b, a)对)。您可以以任意顺序打印这些对。如果有多种方式选择城市和连接,以获得最低价的建设,然后打印其中任何一个。

Examples

input

Copy

3
2 3
1 1
3 2
3 2 3
3 2 3

output

Copy

8
3
1 2 3 
0

input

Copy

3
2 1
1 2
3 3
23 2 23
3 2 3

output

Copy

27
1
2 
2
1 2
2 3

题解:
把每个城市,连一个到超级源点的边,边权为c,接着每两个点连接,加权

跑最小生成树板子即可

连一个到超级源点的边其实就是判断,到底是连边还是在这个点建电站,为什么可行,因为这样的话,在排序时,就把最优情况放在前面了,

#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
#define int long long
typedef pair<int,int> PII;
struct node
{
	int x,y,c,k;
}a[2005];
struct nod
{
	int fa,ne,w; 
}p[4000040];
int cnt = 0;
int sum = 0;
vector<int> ans;
vector<PII> res; 
int f[2005];
int find(int x)
{
	if(f[x] == x)
	return x;
	return f[x] = find(f[x]); 
}
bool cmp(nod a,nod b)
{
	return a.w < b.w;
} 
void solve()
{
	int n;
	cin >> n; 
	for(int i = 1;i <= n;i++)
	{
		cin >> a[i].x >> a[i].y;
	}
	for(int i = 1;i <= n;i++)
	f[i] = i;
	for(int i = 1;i <= n;i++)
	{
		cin >> a[i].c;
		p[++cnt].fa = 0;
		p[cnt].ne = i;
		p[cnt].w = a[i].c;
	}
	for(int i = 1;i <= n;i++)
	{
		cin >> a[i].k;
	}
	for(int i = 1;i <= n;i++)
	{
		for(int j = i + 1;j <= n;j++)
		{
			p[++cnt].fa = i;
			p[cnt].ne = j;
			p[cnt].w = (abs(a[i].x - a[j].x) + abs(a[i].y - a[j].y))*(a[i].k + a[j].k);
		}
	}
	sort(p + 1,p +1 + cnt,cmp);
	int s = 0;
	for(int i = 1;i <= cnt;i++)
	{
		int x = find(p[i].fa);
		int y = find(p[i].ne);
		if(x == y)
		{
			continue;
		}
		if(p[i].fa == 0)
		{
			ans.push_back(p[i].ne);
		}
		else
		{
			res.push_back({p[i].fa,p[i].ne});
		}
		f[x] = y;
		sum += p[i].w;
		s++; 
		if(s == n)
		break;
	}
	cout << sum <<"\n";
	cout << ans.size() <<"\n";
	for(auto i:ans)	
	cout <<i << ' ';
	cout <<"\n";
	cout << res.size() <<"\n";
	for(auto t:res)
	{
		cout <<t.first <<" "<<t.second <<"\n";
	}
}


signed main()
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);cout.tie(0);
	int t = 1;
//	cin >> t;
	while(t--)
	{
		solve(); 
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值