BAPC 2020 G题 Generator Grid

题目:

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值