hud 1811 Rank of Tetris

题目

http://acm.hdu.edu.cn/showproblem.php?pid=1811

分析

思路不是自己的,这次纯粹当时学习了。
是一道拓扑排序题, 但是因为多了个等号,所以增加了点难度,这题的关键也在于怎样处理这个等号。相等的那些数,其实都是同一个数,所以需要先进行预处理,把所有相同的那些数,只用其中的一个来代表,所以,可以用并查集来把相同的数并成一颗树,之后都是用这个树根的数来代替这个树中所有的数。另外,注意去重。最后,就是对于处理好的数据使用拓扑排序。


因为有的点:a == b, 则用并查集把两者并入同一个集合,看成是一个整体(一个单位), 所有点以根结点建图。
邻接表实现的拓扑排序:
1.找出入度为零的顶点dot(根结点建图), 进入队列,并更新此时已经找到的入度为0节点的个数。
2.当队列有两个含两个以上的点时,记录flag为1,表示信息不完整。(因为这几个入度为0的点之间没有联系,排序的时候无法判断,而且可能剩下的图有环, 出现信息冲突,因此此处就算知道可能会信息不完整也不能马上return,要继续运行
3.判断是否有信息冲突)删除含有dot点的边, 减少与dot相联系的其他的点入度, 当其他点入度为零时, 进入队列。
4.重复步骤2和3,直到队列为空。
5.若入度为0点的个数和题目给出的点个数N不同,则表示有环,发生信息冲突。
6.若入度为0点的个数和题目给出的点个数N相同,且flag为1则表示信息不完整,否则可以进行排序


此题目的分析中判断出先处理A=B的情况,将A和B处理成一个点(本题用集合来合并二者,以后如果用到A或者B,则用树根表示)是关键,原因如下:
如果按照顺序处理,在建图的时候无法处理A=B的情况,如果不添加A和B间的关系,则无法处理A=B,A>C,C>B的情况;如果转换成A>B,B>A则无法处理C>A,C<B,A=B的情况。
因此好的做法就是先将A=B的情况合并成一个点,这样就可以很好处理之后遇到的关系了。

复杂度

空间复杂度为O(N+M),建立一个集合的时间复杂度为O(1),N次合并M次查找的时间复杂度为O(MAlpha(N)),这里Alpha是Ackerman函数的某个反函数,在很大的范围内(人类目前观测到的宇宙范围估算有10的80次方个原子,这小于前面所说的范围)这个函数的值可以看成是不大于4的,所以并查集的操作可以看做是线性的。

涉及内容

数据结构:并查集

图论:拓扑排序

感想

第一次做混合两种想法的题目,花了大概三天时间始终没有搞定,最后看了结题报告,感觉这确实是一道好题,混合了并查集和图论中的基本知识。同时,发现自己在图论方面比较弱,需要做题加强。
通过接着一道题目,我觉得在看过网上的思路之后,应该按照自己的理解先敲一遍代码,然后对比分析,这样效果可能会好一些。其次,当遇到多种算法混合问题的时候,心里要清楚以哪种算法为重点(即最终解题用的是哪种算法),哪种算法为辅助(即辅助生成能够使用解题算法的辅助数据)。本题目中拓扑排序时重点,并查集是辅助处理A=B的情况,从而让题目可以顺利使用图论的拓扑排序算法。

代码

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

typedef struct Node1811
{
	int p,in; vector<int> rect;
} Node1811;
Node1811 f1811[10005];

typedef struct Elem1811
{
	int i,j; char op;
} Elem1811;
Elem1811 e1811[20005];

queue<int> q1811;
int N,M,pos;

void makeset1822()
{
	for(int i=0;i<10005;++i)
		f1811[i].p=i,f1811[i].in=0,f1811[i].rect.clear();
	while(!q1811.empty()) q1811.pop();
}

int find1811(int x)
{
	return x == f1811[x].p ? x : (f1811[x].p = find1811(f1811[x].p));//路径压缩
}

void union1811(int i,int j)//主要用于处理A=B的情况
{
	int a=find1811(i);
	int b=find1811(j);
	if(a==b) return;
	f1811[b].p=a;
	//f1811[a].p=b;//由于本函数主要用于处理A=B的情况,所以可以用于替换上边的两句
}

int tuopusort1811()
{
	int result=0,data;
	for(int i=0;i<N;++i)
		if(find1811(i)==i && f1811[i].in==0)
			q1811.push(i);
	while(!q1811.empty())
	{
		//如果大于1,说明这些点之间没有任何关系,故在排序的时候属于UNCERTAIN
		//并且程序不能立即返回,因为题目要求是“如果信息中同时包含冲突且信息不完全,就输出CONFLICT”,即UNCERTAIN优先级低,因此需要继续运行判断是否出现CONFLICT
		if(q1811.size()>1) result=2;
		data=q1811.front();q1811.pop();--pos;
		for(int i=0;i<f1811[data].rect.size();++i)
		{
			if(--f1811[ f1811[data].rect[i] ].in==0) q1811.push(f1811[data].rect[i]);//可以用于替换下边的两句,如果减到0,下次肯定减到-1,判断条件不成立,所以不会重复进队列
			//if(f1811[ f1811[data].rect[i] ].in>0) --(f1811[ f1811[data].rect[i] ].in);
			//if(f1811[ f1811[data].rect[i] ].in==0) q1811.push(f1811[data].rect[i]);
		}
	}
	if(pos > 0) return 1;//存在环,说明CONFLICT
	return result;
}

int main()
{
	//freopen("in.txt","r",stdin);
	int flag;
	while(cin>>N>>M)
	{
		pos=N;
		flag=0,makeset1822();
		for(int i=0;i<M;++i)
		{
			cin>>e1811[i].i>>e1811[i].op>>e1811[i].j;
			if(e1811[i].op == '=')
				union1811(e1811[i].i,e1811[i].j),--pos;
		}

		for(int i=0;i<M;++i)
		{
			if(flag==1 || e1811[i].op == '=') continue;
			int a=find1811(e1811[i].i);
			int b=find1811(e1811[i].j);
			if(a == b)//冲突
				flag=1;
			switch(e1811[i].op)
			{
				case '>':{
					//if(find(f1811[a].rect.begin(),f1811[a].rect.end(),b)==f1811[a].rect.end())//保证同一元素不会重复出现在父节点的vector中
					{
						++f1811[b].in;
						f1811[a].rect.push_back(b);
					}
						 }break;
				case '<':{
					//if(find(f1811[b].rect.begin(),f1811[b].rect.end(),a)==f1811[b].rect.end())//保证同一元素不会重复出现在父节点的vector中  
					{
						++f1811[a].in;
						f1811[b].rect.push_back(a);//该处会导致同一元素重复出现在父节点的vector中,但是tuopusort()函数保证重复元素不会重复进队列
					}
						 }break;
			}
			
		}
		if(flag!=1)
			flag=tuopusort1811();
		switch(flag)
		{
			case 1:cout<<"CONFLICT"<<endl;break;
			case 2:cout<<"UNCERTAIN"<<endl;break;
			default:cout<<"OK"<<endl;
		}
	}
	return 0;
}

参考文献

http://blog.csdn.net/xymscau/article/details/7185828 参考了代码

http://gzhu-101majia.iteye.com/blog/1284183 可以借鉴题目的分析思路

http://www.icedy.com/?p=1032 可以借鉴题目的分析思路,他的代码时间似乎短一些

http://www.cnblogs.com/kane0526/archive/2013/01/11/2856890.html 可以借鉴结题思路

你可能感兴趣的:(编程,算法,语言,拓扑排序,并查集)