StkOvflow

STACK OVERFLOW!

一言(ヒトコト)

又把1e3+7写成1e4+7了……
干脆叫万柒吧。。
——yxy

AcWing. 1146 新的开始

传送门

题目大意

给一张图,每个点有对应的点权,每条边有对应的边权。可以有如下几种选择:

1.选择一个没通电的点,花费vi
2.将两个点连边(要有一点通电),边权pi,j
经过上述操作之后,要使全图通电

解题思路

一眼看上去有一些麻烦,原因是有点权的存在,导致了这个问题求解需要从点和边两方面去考虑,而且还有“通电”这一限制,所以就导致这题看起来很困难。

那我们就可以换一个角度思考,能否将点权转化为边权呢?联系之前求解最短路用的虚拟源点,我们可以把所有点向超级源点S连一条边,权值是它的点权vi,这样我们选择点变成了选择边,这样我们再来看通电这一个限制如何解决。

当我们假定S源点是通电的(这样操作1才能进行),它连向的点就是新开的矿井,这样操作1相当于两个点通电->不通电的连线,边权是vi

由于一开始这张图上的所有点都是不通电的,所以操作1至少操作1次,在经历了1次操作1之后,这张图上要通电,就是将其它点和已经通电的点连接,当已经通电的点只有1个时,剩下的点中选出一个,要么和S连边(操作1),要么和这个通电的点连边,所以我们这个包含了S的图通电之后,必定是连通的,那最小费用就是这张图中的最小生成树,用Kruskal算法跑就行了。

关于建图

这题的建图无非两种
一开始读入点权的时候顺便把点和S连边,后面读入边权正常连边就行,对于pi,j,连一条i<>j的无向边,边权为pi,j。用一个变量ecnt统计边数即可(当然,也可以使用vector

代码

普通

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 310, M = N * (N + 1);
int p[M], n, S, ecnt;

struct Edge 
{
    int u, v, w;
    bool operator <(const Edge& W) const {
        return w < W.w;
    }
} edge[M];

int find(int x) 
{
    if (x != p[x]) p[x] = find(p[x]);
    return p[x];
}

int main() 
{
    scanf("%d", &n);
    
    for (int i = 1; i <= n; i ++ ) 
    {
        int x;
        scanf("%d", &x);
        edge[++ ecnt] = {0, i, x};
    }
    
    for (int i = 1; i <= n; i ++ ) 
        for (int j = 1; j <= n; j ++ ) 
        {
            int x; scanf("%d", &x);
            edge[++ ecnt] = {i, j, x};
        }
    
    sort(edge + 1, edge + ecnt + 1);
    for (int i = 1; i <= ecnt; i ++ ) p[i] = i;
    
    int res = 0;
    for (int i = 1; i <= ecnt; i ++ ) 
    {
        int fu = find(edge[i].u), fv = find(edge[i].v);
        if (fu == fv) continue ;
        
        p[fu] = fv, res += edge[i].w;
    }
    printf("%d\n", res);
    
    return 0;
}

vector

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 310, M = N * (N + 1);
int p[M], n, S, ecnt;

struct Edge 
{
    int u, v, w;
    bool operator <(const Edge& W) const {
        return w < W.w;
    }
} ; vector<Edge> edge;

int find(int x) 
{
    if (x != p[x]) p[x] = find(p[x]);
    return p[x];
}

int main() 
{
    scanf("%d", &n);
    
    for (int i = 1; i <= n; i ++ ) 
    {
        int x;
        scanf("%d", &x);
        edge.push_back({S, i, x});
    }
    
    for (int i = 1; i <= n; i ++ ) 
        for (int j = 1; j <= n; j ++ ) 
        {
            int x; scanf("%d", &x);
            edge.push_back({i, j, x});
        }
    ecnt = edge.size();
    
    sort(edge.begin(), edge.end());
    for (int i = 0; i <= ecnt; i ++ ) p[i] = i;
    
    int res = 0;
    for (int i = 0; i < ecnt; i ++ ) 
    {
        int fu = find(edge[i].u), fv = find(edge[i].v);
        if (fu == fv) continue ;
        
        p[fu] = fv, res += edge[i].w;
    }
    printf("%d\n", res);
    
    return 0;
}
posted @   StkOvflow  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示