<九度 OJ>题目1012:畅通project

题目描写叙述:

某省调查城镇交通状况,得到现有城镇道路统计表。表中列出了每条道路直接连通的城镇。省政府“畅通project”的目标是使全省不论什么两个城镇间都能够实现交通(但不一定有直接的道路相连,仅仅要互相间接通过道路可达就可以)。

问最少还须要建设多少条道路?

输入:

測试输入包括若干測试用例。每一个測试用例的第1行给出两个正整数。各自是城镇数目N ( < 1000 )和道路数目M;随后的M行相应M条道路,每行给出一对正整数,各自是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。

注意:两个城市之间能够有多条道路相通,也就是说

3 3

1 2

1 2

2 1

这样的输入也是合法的

当N为0时,输入结束,该用例不被处理。

输出:

对每一个測试用例,在1行里输出最少还须要建设的道路数目。

例子输入:
4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0
例子输出:
1
0
2
998

分析:

并查集的简单应用,用并查集联立m对已经联通的城镇。联立后在一个集合的点将仅仅有一个公共的最高祖先。最后查看孤立城镇有多少个就可以。

#include "vector"
#include "string"
#include "algorithm"
#include <iostream>
#include "stack"
#include <cmath>
#include <set>

using namespace std;

class UFSet
{
public:
    UFSet(int nsize)
    {
        size = nsize;
        parent = new int[size];
    };
    ~UFSet()
    {
        delete[] parent;
        parent = NULL;
    };
    void makeSet(int n);////初始化每个元素的祖先为自身
    int findSet(int x);//找到元素x的祖先元素parent[x]
    void unionSet(int a, int b);//若两个元素的祖先不同,则将x元素的祖先设置为y元素的祖先
    int getSets(int n);//获取独立的集合数量
private:
    int *parent;//存放祖先节点,比如x=parent[i]。元素i的祖先节点为元素x
    int size;
};

void UFSet::makeSet(int n) //初始化
{
    //初始化每个元素都各自为一个独立的集合。其祖先均设定为自身
    for (size_t i = 1; i <= n; i++)
        parent[i] = i;
}

int UFSet::findSet(int x)
{
    //找到元素所在的集合。也就是找到自己的最高的祖先。
    //这也是推断两个元素是否在同一个集合中的主要根据。
    if (parent[x] == x)//递归截止条件(最高祖先的祖先是其自身)
        return x;

    parent[x] = findSet(parent[x]);//递归,终于找到x的最高祖先。而且沿途找到全部的最高祖先
    return parent[x];
}

void UFSet::unionSet(int x, int y)
{
    //将x和y所在的集合进行合并,利用findSet()推断x和y所在的集合是否同样,
    //假设不同,则要把当中一个元素的祖先指向还有一个元素的祖先。

int ux = findSet(x);//获取节点x的祖先
    int uy = findSet(y);
    if (ux != uy)
        parent[ux] = uy;
}

int UFSet::getSets(int n)
{
    int count = 0;
    for (int i = 1; i <= n; i++)
    {//假设存在某一个节点的祖先是自身说明他是孤立的
        if (parent[i] == i)
            count++;
    }
    return count;
}

int main()
{
    int m, n;
    while (cin >> n >> m)
    {
        UFSet uset(10000);
        uset.makeSet(n);//初始化
        //接收m对已经联通的城镇
        int x = 0, y = 0;
        for (int i = 0; i<m; i++)
        {
            cin >> x >> y;//注:这里数组下标位置代表城镇编号
            uset.unionSet(x, y);
        }
        cout << uset.getSets(n)-1 << endl;

    }
    return 0;
}
/**************************************************************
    Problem: 1012
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1520 kb
****************************************************************/

注:本博文为EbowTang原创,兴许可能继续更新本文。

假设转载。请务必复制本条信息!

原文地址:http://blog.csdn.net/ebowtang/article/details/50515067

原作者博客:http://blog.csdn.net/ebowtang

时间: 2024-10-08 13:27:08

&lt;九度 OJ&gt;题目1012:畅通project的相关文章

【九度OJ】题目1054:字符串内排序

题目描述: 输入一个字符串,长度小于等于200,然后将输出按字符顺序升序排序后的字符串. 输入: 测试数据有多组,输入字符串. 输出: 对于每组输入,输出处理后的结果. 样例输入: bacd 样例输出: abcd #include <iostream> using namespace std; int main() { string str; while(cin >> str) { for(int i = str.length() - 1; i >= 0; i--) { fo

【九度OJ】题目1061:成绩排序

题目描述: 有N个学生的数据,将学生数据按成绩高低排序,如果成绩相同则按姓名字符的字母序排序,如果姓名的字母序也相同则按照学生的年龄排序,并输出N个学生排序后的信息. 输入: 测试数据有多组,每组输入第一行有一个整数N(N<=1000),接下来的N行包括N个学生的数据.    每个学生的数据包括姓名(长度不超过100的字符串).年龄(整形数).成绩(小于等于100的正数). 输出: 将学生信息按成绩进行排序,成绩相同的则按姓名的字母序进行排序.    然后输出学生信息,按照如下格式:    姓名

(九度OJ)题目1338:角斗士(状压DP)

题目描述: 角斗士是古罗马奴隶社会的一种特殊身份的奴隶,他们的职责是在角斗场上进行殊死搏斗,为了人们提供野蛮的娱乐.他们的结局或是战死,或者由于表现突出赢得胜利而获得释放. 现在在角斗场里有N个待战的角斗士(1 <=N<=18),每天都将举行一场比赛,为了保持比赛的刺激性,每场比赛前才会在所有当前活着的角斗士之中随机选择两名进行上场拼杀.每场比赛的结束条件即为其中一名被杀死.当进行了N场比赛之后,最后存活的角斗士将被释放.而你将被赋予一个任务,计算出每名角斗士最终存活的概率.我们将提供角斗士之

九度OJ;题目1146:Flipping Pancake

题目链接地址:http://ac.jobdu.com/problem.php?pid=1146 转载请注明本文地址http://blog.csdn.net/yangnanhai93/article/details/42014265 因为问题只要求2n-3次,并没有别的要求,所以最简单一个思想就是没一次循环完成一个目标就是把当前最大的放到最后,那么第一步就是先经过旋转把当前最大的放在数组最前面,第二步就是旋转到对应位置 #include <stdio.h> using namespace std

【九度OJ】题目1111:单词替换

题目1111:单词替换 题目描述: 输入一个字符串,以回车结束(字符串长度<=100).该字符串由若干个单词组成,单词之间用一个空格隔开,所有单词区分大小写.现需要将其中的某个单词替换成另一个单词,并输出替换之后的字符串. 输入: 多组数据.每组数据输入包括3行, 第1行是包含多个单词的字符串 s, 第2行是待替换的单词a,(长度<=100) 第3行是a将被替换的单词b.(长度<=100) s, a, b 最前面和最后面都没有空格. 输出: 每个测试数据输出只有 1 行, 将s中所有单词

【九度OJ】题目1482:玛雅人的密码 (bfs+hash)

题目1482:玛雅人的密码 时间限制:1 秒 内存限制:128 兆 特殊判题:否 提交:2076 解决:513 题目描述: 玛雅人有一种密码,如果字符串中出现连续的2012四个数字就能解开密码.给一个长度为N的字符串,(2=<N<=13)该字符串中只含有0,1,2三种数字,问这个字符串要移位几次才能解开密码,每次只能移动相邻的两个数字.例如02120经过一次移位,可以得到20120,01220,02210,02102,其中20120符合要求,因此输出为1.如果无论移位多少次都解不开密码,输出-

九度OJ:题目1202:排序

1 #include<stdio.h> 2 #include<algorithm> 3 using namespace std; 4 int main() 5 { 6 int num=0,i=0; 7 while(scanf("%d",&num)!=EOF) 8 { 9 int arr[110]; 10 for(i=0 ; i<num ; ++i) 11 scanf("%d",&arr[i]); 12 sort(arr,

九度OJ:题目1476:平方因子 AC

1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<math.h> 4 bool judge(int a) 5 { 6 int sqr=sqrt(a*1.0); 7 for(int i=2 ; i<=sqr+1 ; ++i) 8 { 9 int tmp=i*i; 10 if(a%tmp==0) 11 return 1; 12 } 13 return 0; 14 } 15 16 int main(int argc,

九度OJ:题目1117:整数奇偶排序

1 #include<stdio.h> 2 #include<algorithm> 3 using namespace std; 4 const int N=10; 5 int main() 6 { 7 int arr[10],odd[10],even[10]; 8 while(scanf("%d",&arr[0])!=EOF) 9 { 10 for(int i=1 ; i<N ; ++i) 11 scanf("%d",&