首页 > 技术文章 > zoj 2833 friendship

grandj 2014-04-13 15:48 原文

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

 

这次还发现了以前犯得一个蠢爆了的问题,真是气死我了!

 

推荐阅读