poj-1861

来源:互联网 发布:三国杀网络错误请重试 编辑:程序博客网 时间:2024/04/27 07:09
// 596K    141MS   G++#include <cstdio>#include <cstring>#include <algorithm>using namespace std;struct Connetcions {    int begin;    int end;    int length;    char left;};int cmp(const void * a, const void * b) {    return (*((Connetcions *)a)).length - (*((Connetcions *)b)).length;}struct union_find_member {    int setId; // begin from 1, 0 means not filled yet.    // int Prev;    // int prevLength;};typedef struct union_find_member union_find_member;typedef struct Connetcions Connetcions;union_find_member UF_set[1010];Connetcions connections[15010];int leftConnectionsNum;int hubNum;int connectionNum;int maxlength = 0;int getSetId(int nodeId) {    if (UF_set[nodeId].setId == 0) {        return 0;    }    int curSetId = UF_set[nodeId].setId;    while(UF_set[curSetId].setId != curSetId) {        curSetId = UF_set[curSetId].setId;    }    UF_set[nodeId].setId = curSetId;    return curSetId;}char UF_fill(int beginId, int endId, int connectionlength) {    int beginSetId = getSetId(beginId);    int endSetId = getSetId(endId);    // printf("%d -> %d, %d -> %d\n", beginId, beginSetId, endId, endSetId);    // if begin and end all no filled before    if (beginSetId == 0 && endSetId == 0) {        UF_set[beginId].setId = beginId;        UF_set[endId].setId = beginId;    } else if (!beginSetId && endSetId) {        UF_set[beginId].setId = endSetId;    } else if (beginSetId && !endSetId) {        UF_set[endId].setId = beginSetId;        // printf("A %d %d\n", beginSetId, UF_set[endId].setId);    } else if (beginSetId && endSetId) {        if (beginSetId != endSetId) {            UF_set[endSetId].setId = beginSetId;            UF_set[endId].setId = beginSetId;        } else {            // has all filled, no need this cable, and becuase sorted before,            // so it must >= current cable.            return 0;        }    }    return 1;}int main() {    while(scanf("%d %d", &hubNum, &connectionNum) != EOF) {        maxlength = 0;        memset(UF_set, 0, sizeof(UF_set));        memset(connections, 0, sizeof(connections));        leftConnectionsNum = 0;        for (int i = 1; i <= connectionNum; i++) {            int beginId;            int endId;            int connectionlength;            scanf("%d %d %d", &beginId, &endId, &connectionlength);            connections[i-1].begin = beginId;            connections[i-1].end = endId;            connections[i-1].length = connectionlength;        }        qsort(connections, connectionNum, sizeof(Connetcions), cmp);        for (int i = 0; i < connectionNum; i++) {            // printf("%d %d %d\n", connections[i].begin,                    // connections[i].end, connections[i].length);            if (UF_fill(connections[i].begin, connections[i].end,                            connections[i].length)) {                connections[i].left = 1;                maxlength = connections[i].length > maxlength ?                            connections[i].length: maxlength;                leftConnectionsNum++;            }        }        printf("%d\n%d\n", maxlength, leftConnectionsNum);        for (int i = 0; i < connectionNum; i++) {            if (connections[i].left) {                printf("%d %d\n", connections[i].begin, connections[i].end);            }        }    }}

算是道并查集的简单题,不过我一开始被搞晕了,纠结于最短路径的问题,并且,一开始,还想着把hub之前的连接关系直接集成到并查集里做,但是后面才发现,简直是自坑,因为并查集这种数据结构不适合来存储这种关系(其实真存也行的), 就另开一个数组来储存最后可以被留下来的cable连接,这道题其实也可以用最小生成树做的。

用并查集做,有个很关键的预处理步骤,那就是把所有输入的cable 按照 长度来进行从小达大的排序,这样才能达到题目的目的,尽量的保留长度最短,并且尽量去掉多余的cable,那么接下来就是并查集的标准操作了,并查集在这里的作用,就是检查输入的两个hub是否已经能被之前的cabl连通了,只需判断这些hub是否属于并查集的同一个集即可(因为这里的cable是双向的), 对于输入的一个cable,有两个hub, A 和B,那么,在将其加入到并查集中时,会有这些case:

case1: A 和 B 之前都没有被添加过, 那么直接将A 和B做为一个集, A作为B的集合Id.

case2: A添加过,B没有添加过,那么直接将B加入到A的集合中,B的集合id 是 A的集合Id.

case3: 和case2相反,A B倒换.

case4: A和B之前都已经被添加过了,又会有两个子case:

         sub-case1: A 和 B的集合Id一样,说明之前加入的cable已经能够将A 与 B连通,并且因为之前已经排过序,因此之前的cable各自的长度一定<=当前这段cable,

                           那么,按照题意,这段cable可以被去掉,直接pass,这里显示出了排序的重要性,否则,可能虽然A B都连通了,但是连接他们的cable可能比这次的要长, 注意题目   没有要求从长度最短,而是要求一段cable最短。

         sub-case2: A 和 B不一个集合,那么就将B的set的top元素的setId设为A的setId, 即将此B所属集合并入到A的集合。

在上面的处理过程中,还要收集被留下来的cable的长度最大值作为输出.

0 0
原创粉丝点击