poj 3723 Kruskal最小生成树

题意:

  • 一堆男女加进一个组,每人的加入费用是10000元。男女之间存在一种亲密度,在加入一个人的时候,ta的加入费是10000减去已经入组的异性中和亲密度最大的。问以某种顺序入组,的最小总费用是多少?

思路:

  • 主要是把这些亲密关系看做无向图,然后要以最小的代价包含所有人,显然是最小生成树。我的做法是,先把有亲密关系的那些人建立无向图,然后求出最小生成树。剩下的人入组费统一10000元。

知识补充:

    • 一个没有圈的连通的无向图就是树,树的边数为顶点数减一。一个没有圈的不连通的无向图就是森林,森林是有很多树组成的森林的边数为定点数减树的数量。树是一个连通无向图边数所能达到的最小情况。
    • 最小生成树的prim算法:首先只有起点为当前点被加入到选定区域中,更新未选定区域中的顶点到当前点的距离为未选定区域顶点到选定区域的距离。然后找出所有未选定区域顶点中据选定区域最近的点,加入选定区域,把该点设为当前点。重复以上步骤,直到所有点都被选中。
    • 最小生成树的Kruskal算法:首先对所有边按照升序排序,然后按照升序依次挑选边加入最小生成树,但是挑选边之前应该先判断这个边是否和前面已经选定的边的顶点形成圈,这时候就要用并查集来高效的判断。如果当前边的两个顶点在同一个连通分量里,那么就会形成圈,不能要这条边,否则可行。
    • 最短路的路径还原办法:这里需要一个prev[max_v]数组,记录当前节点的前驱节点。只需要在最短路算法的没错更新最短路的时候,同时更新对应的前驱节点即可。最后从终点开始还原即可。
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
struct edge{int from, to, cost;}E[50009];
int rank[10008 * 2], par[10008 * 2];

void init(int n) {
    for (int i = 0; i < 10008 * 2; i++) {
        par[i] = i;
        rank[i] = 0;
    }
}

int find(int x) {
    if(par[x] == x) return x;
    else return par[x] = find(par[x]);
}

void unite(int x, int y) {
    x = find(x), y = find (y);
    if (x == y) return;
    if (rank[x] > rank[y]) par[y] = x;
    else {
        par[x] = y;
        if (rank[x] == rank[y]) rank[y]++;
    }
}

bool same(int x, int y) { return find(x) == find(y); }

bool cmp(const edge e1, const edge e2) { return e1.cost < e2.cost;}

int kruskal(int r, int n) {
    int res = 0, count = 1;
    sort(E, E + r, cmp);
    for (int i = 0; i < r; i++) {
        if (!same(E[i].from, E[i].to)) {
            unite(E[i].from, E[i].to);
            res += E[i].cost;
            count++;
        }
    }
    return res + (n - count + 1) * 10000;
}

int main(void) {
    int t;
    scanf("%d", &t);
    while (t--) {
        int n, m, r;
        scanf("%d%d%d", &n, &m, &r);
        n += m;
        init(n);
        for (int i = 0; i < r; i++) {
            scanf("%d%d%d", &E[i].from, &E[i].to, &m);
            E[i].cost = 10000 - m;
            E[i].to += 10000;
        }
        printf("%d\n", kruskal(r, n));
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-09 05:34:04

poj 3723 Kruskal最小生成树的相关文章

poj 3723 Conscription(最小生成树拓展)

Conscription Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7702   Accepted: 2667 Description Windy has a country, and he wants to build an army to protect his country. He has picked up N girls and M boys and wants to collect them to be

POJ 3723.Conscription 最小生成树

Conscription Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 13438   Accepted: 4699 Description Windy has a country, and he wants to build an army to protect his country. He has picked up N girls and M boys and wants to collect them to b

POJ 3723 Conscription 最小生成树 克鲁斯卡尔算法变形

#include <cstdio> #include <iostream> #include <algorithm> #include <queue> #include <stack> #include <cstdlib> #include <cmath> #include <set> #include <map> #include <vector> #include <cstri

POJ 1258-Agri-Net (Kruskal)

题目链接:Agri-Net 最小生成树水题,数组开的和题目描述一样,但是就是RE,有填了个0,还好这个题用 库鲁斯卡尔 敲了一遍,发现了点问题,以前写的库鲁卡尔模板有点问题,多写了步无用的操作,已修正. 题意:就是一个农夫想选镇长....建一条路,使之能到达所有点,距离最短. scanf输入 796K 32MS cin输入 832K 125MS #include <iostream> #include <cstdio> #include <cstring> #inclu

POJ 1258 Agri-Net (最小生成树+Prim)

Agri-Net Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 39820   Accepted: 16192 Description Farmer John has been elected mayor of his town! One of his campaign promises was to bring internet connectivity to all farms in the area. He nee

Prim和Kruskal最小生成树

标题: Prim和Kruskal最小生成树时 限: 2000 ms内存限制: 15000 K总时限: 3000 ms描述: 给出一个矩阵,要求以矩阵方式单步输出生成过程.要求先输出Prim生成过程,再输出Kruskal,每个矩阵输出后换行.注意,题中矩阵表示无向图输入: 结点数矩阵输出: Prim:矩阵输出 Kruskal:矩阵输出输入样例: 3 0 1 3 1 0 2 3 2 0 输出样例: 3 0 1 3 1 0 2 3 2 0Prim: 0 0 0 0 0 0 0 0 0 0 1 0 1

poj 1679 判断最小生成树是否唯一

/* 只需判断等效边和必选边的个数和n-1的关系即可 */ #include<stdio.h> #include<stdlib.h> #define N 110 struct node { int u,v,w; }f[N*N*2]; int cmp(const void *a,const void*b) { return (*(struct node *)a).w-(*(struct node *)b).w; } int pre[N]; int find(int x) { if(x

贪心算法(2)-Kruskal最小生成树

什么是最小生成树? 生成树是相对图来说的,一个图的生成树是一个树并把图的所有顶点连接在一起.一个图可以有许多不同的生成树.一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边.最小生成树其实是最小权重生成树的简称.生成树的权重是考虑到了生成树的每条边的权重的总和. 最小生成树有几条边? 最小生成树有(V – 1)条边,其中V是给定的图的顶点数量. Kruskal算法 下面是步骤寻找MST使用Kruskal算法 1 1,按照所有边的权重

poj 3723 Conscription 【最大生成树|最大权森林】

题目:poj 3723 Conscription 题意:要征兵n个男兵和m个女兵,每个花费10000元,但是如果已经征募的男士兵中有和将要征募的女士兵关系好的,那么可以减少花费,给出关系,求最小花费. 分析:这个题目初始一个是个二分图,以为可以从这里入手,但是这个题目这个性质没用. 初始花费没人10000,那么减去其中有关系的就是当前的花费. 要是花费最少,那么减去的最大即可,又因为没人只征募一次,即最多选择一个,所以减去一个最大生成树就ok AC代码: #include <cstdio> #