zoj 2833 friendship
zoj 2833这次真的很顺利了。。居然是因为数组的大小没有符合要求,瞎折腾了很久。。没有注意到要求范围,真是该死!
想法很简单,就是定义一个父结点数组,下标 i 表示这个元素,初始化为 -1表示 这个元素的朋友只有自己,当parent[i]为负数时,朋友的个数就是|parent[i]| 即绝对值,如果parent[i]为正数,则表示 i的父结点。通过find找到i的根,其中使用了权重合并,即结点少的合并在结点多的树上。注意如果根相同,即已经 是朋友了,就不需要再合并了。 真是好神奇的并查集,将正数负数用得如此淋漓尽致!这次终于算是我独立写出来的了,好高兴!
// // //#include "stdafx.h" #include <stdio.h> #include <iostream> #include"memory.h" using namespace std; #define Maxsize 100000//最多元素个数 int parent[Maxsize]; void WeightedUnion(int i, int j) { //基于权重对根合并,将结点少的合并到结点多的 int temp = parent[i] + parent[j]; if (parent[j] < parent[i])//i的结点比较少 { parent[i] = j;//i 成为j的结点 parent[j] = temp;//j 的结点等于 i+j } else//i的结点多于或等于j 的结点 { parent[j] = i; parent[i] = temp; } } int findparent(int i) { while (parent[i] >= 0)//不为根 { i = parent[i]; } return i; } int main( ) { int n, m, x, y, flag = 0, count = 0; char c; while (scanf_s("%d%d", &n, &m) != EOF) { memset(parent, -1, sizeof(parent));//将每个根置为-1 while (m--) { cin >> c;//gets(c);//scanf_s("%c",&c); if (c == 'M')//M交朋友,调整根的数据 { scanf_s("%d%d", &x, &y); x = findparent(x);//找到自己所在的根 y = findparent(y); if (x != y)//不是同一个根,不为friend { WeightedUnion(x, y); } } else if (c == 'Q')//询问,输出friend个数 { scanf_s("%d", &x); if (flag == 0) { if (count++ != 0) printf("\n"); printf("Case %d:\n", count); flag = 1; } printf("%d\n", -parent[findparent(x)]);//求到根,输出这棵树有多少结点 } } flag = 0; } return 0; }
by the way ,因为vs编译的,如果要AC要将#include "stdafx.h"去掉和将
scanf_s改成scanf
这次还发现了以前犯得一个蠢爆了的问题,真是气死我了!