新的开始-(最小生成树)

咕咕咕

(努力让自己的题解变成认真的题解,但还是忍不住要吐槽,一本通里题目名字为什么都这么中二)

一开始,觉得就是一个最小生成树的裸题。

于是就没想太多,直接,在点权值中取最小值,再直接求最小生成树,求和。

结果凄惨的只拿了50,de了半天bug,甚至怀疑过自己是不是kruskal的板子写错了

还是看了别人的正解,才发现自己思路有漏洞

应该建一个虚拟源点,每个点i连向虚拟源点的边权为发电站费用v[ i ]

为什么呢..?因为虽然是双向边,但存边的时候只能单向存。

这就导致,从哪个点出发,会决定了,有的边加不加的进去。

于是...不能简简单单的取出发电站费用中最少的.

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

inline int read()
{
    int sum = 0,p = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
            p = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (sum *= 10) += ch - '0';
        ch = getchar();
    } 
    return sum * p;
}

const int N = 310; 
int n,ans,tot,cnt;
struct edge
{
    int frm,to,wei;
}e[N * N];
int fa[N];

int findfa(int x)
{
    return fa[x] == x ? x : findfa(fa[x]);
}

bool cmp(edge a,edge b)
{
    return a.wei < b.wei;
}

void kruskal()
{
    sort(e+1,e+cnt+1,cmp);
    for(int i = 0;i <= n;i++)
        fa[i] = i;
    for(int i = 1;i <= cnt;i++)
    {
        int u = findfa(e[i].frm);
        int v = findfa(e[i].to);
        if(u == v)
            continue;
        fa[u] = v;
        ans += e[i].wei;
        if(++tot == n)
            break;
    }
}

int main()
{
    n = read();
    int a;
    for(int i = 1;i <= n;i++)
    {
        a = read();
        e[++cnt].frm = 0;
        e[cnt].to = i;
        e[cnt].wei = a;
    }
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= n;j++)
        {
            a = read();
            if(i == j)
                continue;
            e[++cnt].frm = i;
            e[cnt].to = j;
            e[cnt].wei = a;
        }
    kruskal();
    printf("%d",ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/darlingroot/p/11279242.html