(HDU - 1811 )Rank of Tetris(拓扑+并查集)

题目链接:Problem - 1811 (hdu.edu.cn)

这道题目综合考察了拓扑序列和并查集,刚看到这道题目时,我的想法是对于rating不同的人我们直接按照给定的rating值大小进行连边,而对于rating值相同的人我们根据其人品值进行连边,但这样的想法是错误的,比如给出  3>4,3=5,这样就会有4和5分别向3连一条边,可以确定的是3大于4以及3大于5,但是并未确定4与5的关系,由于5=3,故应该有5大于4,所以我们利用之前的想法并不能很好地处理这种问题,那我们应该怎么做呢?对于rating值相等的元素一定存在唯一的大小关系,所以我们只需要处理rating值不相同的元素之间的关系即可,所以我们可以把rating值相同的元素放入一个集合,在处理之后的关系时我们只需要用集合的代表元素进行判断即可,其余的就是一个基本的拓扑排序问题了。

下面是代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int N=5e5+10;
int n,m,cnt;
int fu[N],h[N],e[N],ne[N],idx,ru[N];
int x[N],y[N],uflag,cflag;
char op[N];
void init()
{
	memset(h,-1,sizeof h);
	memset(ru,0,sizeof ru);
	for(int i=0;i<n;i++) fu[i]=i;
	idx=0;cnt=0;uflag=0;cflag=0;
}
int find(int x)
{
	if(x!=fu[x]) fu[x]=find(fu[x]);
	return fu[x];
}
void add(int x,int y)
{
	e[idx]=y;
	ne[idx]=h[x];
	h[x]=idx++;
}
void topsort()
{
	queue<int> q;
	for(int i=0;i<n;i++)
		if(!ru[i]&&find(i)==i) cnt++,q.push(i);//要保证一个集合最多只能有一个元素入队,即代表元素 
	while(q.size())
	{
		if(q.size()>1) uflag=1;
		int begin=q.front();
		q.pop();
		if(cflag) continue;
		for(int i=h[begin];i!=-1;i=ne[i])
		{
			int j=e[i];
			ru[j]--;
			if(!ru[j])
			{
				q.push(j);
				cnt++;
			}
		}
	}
	if(cnt<n) cflag=1;
}
int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		init();
		for(int i=1;i<=m;i++)
		{
			cin>>x[i]>>op[i]>>y[i];
			//先把rating相同的人放入同一个集合,之后进行操作时只需用集合的代表元素进行操作 
			if(op[i]=='=')
			{
				int u=find(x[i]),v=find(y[i]);
				if(u!=v)
				{
					cnt++;
					fu[u]=v;
				}
			}
		}
		for(int i=1;i<=m;i++)
		{
			if(op[i]=='=') continue;
			int u=find(x[i]),v=find(y[i]);//用集合的代表元素进行操作 
			if(op[i]=='<')
			{
				add(u,v);
				ru[v]++;
			}
			else
			{
				add(v,u);
				ru[u]++;
			}
		}
		topsort();
		if(cflag) puts("CONFLICT");
		else if(uflag) puts("UNCERTAIN");
		else puts("OK");
	}
	return 0;
} 
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值