zoj系列学习——并查集
题型:
并查集 三步走 查找 合并 压缩
问题描述
zoj2833Friendship
题目简析:
已知N个人 M条指令,有两种操作M(朋友关系)Q(查询)
比较典型的并查集问题。
该问题已经提示要用scanf 和 printf了
没有ac的代码,说是超时问题
#include <iostream>
#include<stdio.h>
#include<cmath>
#include <string.h>
using namespace std;
int root_set[100005];
int getroot(int root_set[], int num)
{
while (root_set[num] >= 0)
{
num = root_set[num];
}
return num;
}
void Union(int* root_set, int a, int b)
{
int root1 = getroot(root_set, a);
int root2 = getroot(root_set, b);
if (root1 != root2)
{
root_set[root1] = root_set[root1] + root_set[root2];//因为是负数
root_set[root2] = root1;//相当于合并了
}
return;
}
int getfriends(int* root_set, int a)
{
int root = getroot(root_set, a);
int num = abs(root_set[root]);
return num;
}
int main()
{
int N, M; char ch; int num = 0; int a, b, fre;
while (scanf("%d%d", &N, & M) != EOF)
{
memset(root_set, -1, 100005);
if (num)printf("\n");
num++;
getchar();
printf("Case %d:\n", num);
for (int i = 0; i < M; i++)
{
scanf("%c", &ch);
getchar();
if (ch == 'M')
{
scanf("%d%d", &a, &b);
Union(root_set, a, b);
}
else {
scanf("%d", &fre);
int root = getroot(root_set, fre);
getchar();
printf("%d\n", abs(root_set[root]));
}
}
}
return 0;
}
原因分析:
改进:通过坍塌规则进行算法改进(在查找函数里面添加)
//重新构造
//first是一开始查找的数
while (root_set[first]>=0)
{
int temp = root_set[first];
root_set[first] = num;//此时num是父节点
first = temp;
}
但是解决完这个超时问题后,发现还是wrong了几次answer。
经过查找,发现是memset函数问题。
memset 函数用来对一段内存空间全部设置为某个字符,一般可以对数组初始化。
错误用法:
int root_set[100005];
memset(root_set, -1, 100005);
改进:
void *memset(void *s,int c,size_t n)
总的作用:将已开辟内存空间 s 的首 n 个字节的值设为值 c。
memset(root_set, -1, 4*100005);因为是int 是4个字节
memset(root_set, -1,sizeof(root_set));
getchar()用法
参考:https://www.cnblogs.com/ngnetboy/archive/2012/11/06/2756534.html
getchar()只能输入字符型,输入时遇到回车键才从缓冲区依次提取字符.
问题描述
zoj1789 The Suspects
题目简析:
SARS病毒,问和0号病人一组有多少人。
比较简单
#include <iostream>
#include<stdio.h>
#include<cmath>
#include <string.h>
using namespace std;
int root_set[30002];
int getroot( int num)
{
int first = num;
//找到所有的父节点
while (root_set[num] >= 0)
{
num = root_set[num];
}
//重新构造
while (root_set[first]>=0)
{
int temp = root_set[first];
root_set[first] = num;
first = temp;
}
return num;
}
void Union( int a, int b)
{
int root1 = getroot(a);
int root2 = getroot(b);
if (root1 != root2)
{
root_set[root1] +=root_set[root2];//因为是负数
root_set[root2] = root1;//相当于合并了
}
return;
}
int main()
{
int N, M;
while (cin>>N>>M)
{
if (N == 0 && M == 0)break;
memset(root_set, -1, sizeof(root_set));
for (int i = 0; i < M; i++)
{
int k;
cin >> k;
int num; cin >> num;
for (int t = 1; t < k; t++)
{
int num2; cin >> num2;
Union(num, num2);
}
}
cout << abs(root_set[getroot(0)]) << endl;
}
return 0;
}