题解 【一个人的公司】

传送门

这道题 %10 的数据是为暴搜准备的。

根据题目中的连接成功条件,可以看出这是一题最小生成树,以最小的代价用 n -1 条边连接 n 个点。最小生成树有两种算法, Prim 和 kruskal 。

  • 关于 Prim

它死了。

PrimPrim 的时间复杂度为 O(n^2}) ,本题数据量过大,只能通过 %80 的数据。出题者的意图正是要卡掉 Prim 。而 Kruskal 的时间复杂度为 O(ElogE) ,可以通过本题。

本题重点在于服务器的品牌及判断是否连接成功。

定义数组 b 储存每个服务器的品牌,输入边时判断两端是否为同一品牌,如果成立则边权为零。由于连接线价格等于边权,所以总钱数直接加边权即可。

根据最小生成树定律,如果 n 个点连接成功,则一定用上了 n1 条边。设置计数器 k 记录用上的边个数,如果 k=n1 ,则连接成功。

本题 std :

#include <bits/stdc++.h>
using namespace std;
struct edge {int x, y, v;} a[10000005];
int n, e, b[10000005], f[10000005], ans, k, m;
inline bool cmp(const edge &a, const edge &b) {return a.v < b.v;}
inline int find(int x) {if (f[x] != x) f[x] = find(f[x]); return f[x];}
int main()
{
    scanf("%d%d", &n, &e);
    for (register int i = 1; i <= n; i++) scanf("%d", &b[i]);
    for (register int i = 1; i <= e; i++)
    {
        scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].v);
        // 预处理边权
        if (b[a[i].x] == b[a[i].y]) a[i].v = 0;
    }
    // kruskal
    sort(a + 1, a + 1 + n, cmp);
    for (register int i = 1; i <= n; i++) f[i] = i;
    for (register int i = 1; i <= e; i++)
    {
        if (find(a[i].x) != find(a[i].y))
        {
            ans += a[i].v;
            f[a[i].x] = a[i].y;
            k++;
        }
        if (k == n - 1) break;
    }
    if (k < n - 1) printf("Failed.\n");
    else printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/mhhx/p/11634933.html