您的位置:首页 > 编程语言 > C语言/C++

一道改了很久很久的题 持续更新 直到A过 先放上一些历程

2017-01-19 16:52 176 查看
Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized as a global threat in mid-March 2003. To minimize transmission to others, the best strategy is to separate the suspects from others. In the Not-Spreading-Your-Sickness University (NSYSU), there are many student groups. Students in the same group intercommunicate with each other frequently, and a student may join several groups. To prevent the possible transmissions of SARS, the NSYSU collectsthe member lists of all student groups, and makes the following rule in their standard operation procedure (SOP). Once a member in a group is a suspect, all members in the group are suspects. However, they find that it is not easy to identify all the suspects when a student is recognized as a suspect. Your job is to write a program which finds all the suspects.InputThe input file contains several cases. Each test case begins with two integers n and m in a line, where n is the number of students, and m is the number of groups. You may assume that 0 < n <= 30000 and 0 <= m <= 500. Every student is numbered by a unique integerbetween 0 and n−1, and initially student 0 is recognized as a suspect in all the cases. This line is followed by m member lists of the groups, one line per group. Each line begins with an integer k by itself representing the number of members in the group.Following the number of members, there are k integers representing the students in this group. All the integers in a line are separated by at least one space. A case with n = 0 and m = 0 indicates the end of the input, and need not be processed. 题意:输入的第一个数字为总人数,第二个数字为接下来的分组数。人群当中,“0”这个人是换癌症的   跟他一个组的人也是癌症疑似患者,同理,跟癌症疑似患者一个组的也是癌症疑似患者,要求得到总的癌症疑似患者(包括那个癌症患者“0”)OutputFor each case, output the number of suspects in one line.Sample Input
100 4
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2
200 2
1 5
5 1 2 3 4 5
1 0
0 0
Sample Output
4
1
1

因为这道题是并查集为基础的题   本人最初的思路是这样

对于每一组数据  将其中的元素的值全部定为其中最小那个数的值,等同于将每一组中人的“父亲”都设置为其中最小的那个数的值
因为这样  似乎可以在最后遍历找父节点的时候总能找到0或找不到0,因为都是按照最小的数当做父节点的。
wrong answer
然后将程序写了一遍注释
发现这样写的话  在一个组中,如果并不是值最小的那个人与艾滋患者有联系的话   结果就会少加
于是改进为
扫每一个组中的数据的时候判断其根节点是否为0,如果不是则将这一组全部“父亲”设为这一组中最小那个值
如果任意一个根节点是0,则把这一组所有人的根节点设为0
这样最后似乎就不会找错了
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

int  find(int x);

int pre[30010]; 
int main()
{
int i, all, n, m, j, arr[30010], k, flag = 0, l;
while (scanf("%d%d", &all, &n) != EOF)
{
k = 0;
if (all == 0 && n == 0)continue;
else
{
for (i = 0; i < all; i++)
pre[i] = i;
for (i = 0; i < n; i++)
{
flag = 0;
memset(arr, 0, sizeof(arr));//arr数组用于存放每一组的数据  所以在处理完每一组数据之后清零
scanf("%d", &m);//输入每一组有多少个元素
for (j = 0; j < m; j++)
{
scanf("%d", &arr[j]);//输入元素
if (find(arr[j]) == 0)
{
flag = 1;
}

}
if (flag == 0)
{
sort(arr, arr + m);//将元素排序  以便找到每一组中最小的数字当做根节点
for (l = 1; l < m; l++)//从下标为1开始,因为排序之后arr[0]是最小的
{
pre[arr[l]] = arr[0];//对于每一组数据来说  其在pre数组中的值代表它的上一级节点
}
}
else
{
for (l = 0; l < m; l++)
{
pre[arr[l]] = 0;
}
}
}
}
for (i = 0; i < all; i++)
{
if (find(i) == 0)//对所有给出数据进行遍历,如果它们的根节点等于0,则增加一个值
{
k++;
printf("%d===0\n", i);
}
}
printf("%d\n", k);
}

}

int  find(int x)
{
int fx = x;
while (pre[fx] != fx)
{
fx = pre[fx];
}
return fx;
}
wrong answer
再自己写特殊样例思考
发现如果在扫前一组的时候,0还未出现,那么前面一组的值就只能赋其中最小值的那个  显然也是错误的
所以最终的修改方案应该是完整的并查集思想  我之前一直只用到了查
先写在这里 A 过了回来编辑

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ACM C++ as