2016 UESTC Training for Data Structures H - 郭大侠与英雄学院 CDOJ 1338 并查集

H - 郭大侠与英雄学院

就是给你一个n*m的矩阵,然后叫你缩小这个矩阵,而且每行每列的数之间的大小关系不变,而且全为正数。

开始时想了好久也没想出来

先讨论没有重复点的情况,就是先把所有点按值升序排序,然后依次往新矩阵里放,放时的新的值为max(它所在行的最大值,它所在列的最大值)+1。然后这么放就行

但是有重复点,就比较麻烦了,而且只有同行同列的重复点才会产生影响,就是他们在新矩阵的值必须是一样的,如果不同行不同列,那么就没有影响

然后对于同行同列的相等的数,就必须用并查集把他们放到同一个集合里,

然后就是每行每列的扫过去就行,然后我是用set查的,遇到重复就并查集合并,那并查集用什么来编号呢,我是用的他们的位置,把二维转一维后按位置编号,这样编号就唯一啦,然后后面操作也方便

然后也是按值升序sort,然后从小到大往里面放数

还是考虑重复的情况,对于同一行同一列,相同数必须也要有对应的相同的新值,但是我们是按值的大小放的,所以所有相同的值会连续的放完,然后再放下一批相同的数,这样的话,我们就需要保存每行每列上的最大值,和这个最大值对应的之前的值的所在集合的根节点的那个编号,为什么要保存这个呢,首先要保存最大值是肯定的,然后因为考虑到相同的值是同一个集合嘛,所以要保存最大值所在集合的编号

然后后面更新的时候,如果发现当前值所在集合的编号和目前所在行/列的最大值的编号一样,就说明已经出现过了,不要再处理了,然后如果不一样的话,就是max(当前值所在集合的对应值,行最大值+1),然后再max(当前值所在集合的对应值,列最大值+1)。当然,我把所有数的初始对应值都设为0

然后因为我们所有同一集合里的数必须有相同的新值,所以我们更新时更新的是这个数的根节点的对应值,

这样操作完之后,就该输出啦,输出时我们也是输出这个点的根节点的新值就好啦

end


代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
#define ll long long
#define maxn 1000005
int n, m;
struct Node
{
	int num, idx;
	void make(int n, int i)
	{
		num=n,idx=i;
	}
	bool operator <(Node x)const
	{
		return num < x.num;
	}
	bool operator ==(Node x)const
	{
		return num == x.num;
	}
	bool operator <=(Node x)const
	{
		return num <= x.num;
	}
}grid[maxn], row[maxn], column[maxn];
int aim[maxn];
int parent[maxn];
int size[maxn];//结点数
void init_parent()
{
	for (int i = 0; i<maxn; ++i)
	{
		parent[i] = i;
		size[i] = 1;
	}
}
int findparent(int x)//路径压缩
{
	if (x == parent[x])
		return x;
	else
		return parent[x] = findparent(parent[x]);
}
void unionparent(int x, int y)//启发式合并
{
	int fx = findparent(x);
	int fy = findparent(y);
	if (fy == fx)
		return;
	if (size[fx] >= size[fy])
	{
		size[fx] += size[fy];
		parent[fy] = fx;
	}
	else
	{
		size[fy] += size[fx];
		parent[fx] = fy;
	}
}
int main()
{
	//freopen("input.txt", "r", stdin);
	scanf("%d%d", &n, &m);
	init_parent();
	for (int i = 0; i < n; ++i)
		for (int j = 0; j < m; ++j)
		{
			scanf("%d", &grid[i*m + j].num);
			grid[i*m + j].idx = i*m + j;
		}
	set<Node> tmp;
	set<Node>::iterator itor;
	for (int i = 0; i < n; ++i)
	{
		tmp.clear();
		for (int j = 0; j < m; ++j)
		{
			itor = tmp.find(grid[i*m + j]);
			if (itor == tmp.end() || itor->num != grid[i*m + j].num)
				tmp.insert(grid[i*m + j]);
			else
				unionparent(itor->idx, grid[i*m + j].idx);
		}
	}
	for (int i = 0; i < m; ++i)
	{
		tmp.clear();
		for (int j = 0; j < n; ++j)
		{
			itor = tmp.find(grid[j*m + i]);
			if (itor == tmp.end() || itor->num != grid[j* m + i].num)
				tmp.insert(grid[j*m + i]);
			else
				unionparent(itor->idx, grid[j*m + i].idx);
		}
	}
	/*for (int i = 0; i < n*m; ++i)
		printf("%d ", findparent(i));
	printf("\n");*/
	sort(grid, grid + n*m);
	/*for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < m; ++j)
			printf("%d %d\n", grid[i*m + j].num, grid[i*m + j].idx);
	}
	printf("\n");*/
	for (int i = 0; i < n*m; ++i)
		row[i].idx = -1, column[i].idx = -1;
	for (int i = 0; i < n*m; ++i)
	{
		int idx = grid[i].idx;
		int pa = findparent(idx);
		if (row[idx/m].idx!=pa)
			aim[pa] = max(aim[pa], row[idx / m].num + 1);
		if (column[idx%m].idx != pa)
			aim[pa] = max(aim[pa], column[idx%m].num + 1);
		//row[idx / m] = max(row[idx / m], aim[pa]);
		row[idx / m].make(aim[pa], pa);
		column[idx%m].make(aim[pa], pa);
		//column[idx%m] = max(column[idx%m], aim[pa]);
		//printf("%d %d %d %d\n", pa, aim[pa], row[idx / m], column[idx%m]);
	}
	//printf("ans:\n");
	for (int i = 0; i < n; ++i)
	{
		//printf("%d", aim[findparent(i*n)]);
		for (int j = 0; j < m; ++j)
			printf("%d ", aim[findparent(i*m + j)]);
		printf("\n");
	}
	//system("pause");
	//while (1);
	return 0;
}


你可能感兴趣的:(2016 UESTC Training for Data Structures H - 郭大侠与英雄学院 CDOJ 1338 并查集)