题目:
The volcanic island of Fleeland has never had a proper electric net, but finally the Biomass Alternative Power Conglomerate(BAPC) has agreed to build the island’s power plants and net-work.
On the island’s coast are its n cities. The BAPC has surveyed the cities and proposed m of them as possible locations for a power plant, with the ith proposal stating that the company can build a plant in city ci for cost ai.
These power plants are very modern and a single plant could power the whole island, but the volcano makes building power lines across the island a dangerous affair. For 1 ≤ i < n, the company can build power lines between cities i and i + 1 for a cost of bi, and between cities n and 1 for a cost of bn. A city will receive power if it contains a power plant or is connected to a city with a power plant via power lines.
What is the cheapest way to power all the cities on the island?
输入:
The input consists of:
• One line containing two integers n (3 ≤ n ≤ 105) and m (1 ≤ m ≤ n), the number of cities and the number of possible locations for a power plant.
• Then follow m lines, the ith of which contains ci (1 ≤ ci ≤ n) and ai (1 ≤ ai ≤ 109),the ith possible location for a power plant, and the cost to build it.
• Then follows a line containing n integers bi (1 ≤ bi ≤ 109), the costs of building the power lines.
The values of c1, . . . , cm are unique and given in strictly increasing order.
输出:
Output the minimal cost of powering all cities on the island.
样例:
Sample Input 1
3 2
1 100
2 200
150 300 150
Sample Output 1
400
Sample Input 2
3 2
1 100
2 200
300 300 150
Sample Output 2
450
tag:
最小生成树
题意:
岛上有n座城市,其中m座城市适合作为发电厂
1.在城市ci修建一座发电厂花费ai.
2.对于1<i<n,在城市ci与城市ci+1之间修建电力线花费bi
在城市ci与城市c1之间修建电力线花费bi
3.如果一个城市包含一个发电厂,或者通过电力线与一个有发电厂的城市相连,那么这个城市将获得电力
思路:
将灯塔费用转化成0点与这个点之间电线费用,就可以把在城市建立发电厂也转化为建电线
只需要按照电线的花费从小到大,使所有的城市通电就行了。
若当前城市已经与其他城市相连通电,则无需操作。
代码
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int N=1e5+5;
const int INF=0x3f3f3f3f;
int n,m;//n是点数,m是边数
struct Edge{//存储边
int a;
int b;
int w;//边的权重
bool operator< (const Edge &W)const{//重载小于号,按照边的权重从小到大排序
return w < W.w;
}
}edge[N*2];
int p[N];//并查集的父节点数组
int find(int x)//并查集查找祖宗结点
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
ll kruskal(){
sort(edge+1,edge+1+m+n);//所有边排序
for(int i=1;i<=n;i++){//初始化并查集
p[i]=i;
}
ll res=0,cnt=0;//res是当前最小生成树的权重和,cnt是当前存的多少条边
//从小到大枚举所有边
for(int i=1;i<=m+n;i++){
int a=edge[i].a,b=edge[i].b,w=edge[i].w;
//cout << a << " " << b << " " << w << endl;
a=find(a),b=find(b);
if(a!=b){//两祖宗结点不连通
p[a]=b;//合并
res+=w;//加权重
cnt++;//存的边个数相加
}
}
if(cnt<n-1){//不连通
return INF;
}
return res;//返回权重之和
}
int main()
{
cin >> n >> m;//n是点数,m是边数
//将灯塔费用转化成0点与这个点之间电线费用
for(int i=1;i<=m;i++){
edge[i].a=0;
cin >> edge[i].b;
cin >> edge[i].w;
}
//存入边
for(int i=1;i<=n-1;i++){
edge[i+m].a=i;
edge[i+m].b=i+1;
cin >> edge[i+m].w;
}
edge[m+n].a=n,edge[m+n].b=1;
cin >> edge[m+n].w;
//计算最小生成树的权重之和
cout << kruskal() << endl;
return 0;
}
//kruskal:
//时间复杂度O(mlogm)
/**
1.将所有边按权重从小到大排序
2.枚举每条边ab,权重c
如果ab不连通,将这条边加入到集合中
**/
int n, m; // n是点数,m是边数
int p[N]; // 并查集的父节点数组
struct Edge // 存储边
{
int a, b, w;
bool operator< (const Edge &W)const
{
return w < W.w;
}
}edges[M];
int find(int x) // 并查集核心操作
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int kruskal()
{
sort(edges, edges + m);
for (int i = 1; i <= n; i ++ ) p[i] = i; // 初始化并查集
int res = 0, cnt = 0;
for (int i = 0; i < m; i ++ )
{
int a = edges[i].a, b = edges[i].b, w = edges[i].w;
a = find(a), b = find(b);
if (a != b) // 如果不连通,则将其合并
{
p[a] = b;
res += w;
cnt ++ ;
}
}
if (cnt < n - 1) return INF;
return res;
}