HDU1811(Rank of Tetris)

题目传送门
在这里插入图片描述

题意

就是给一个榜单严格按照rating和人品来排序,问能不能排列好,如果能排列好输出"OK",如果存在信息不全,也就是可能A > B,C > B,但是A和C无法确定大小那就信息不全输出"UNCERTAIN"。其他情况就输出"CONFLICT"。

思路

拓扑排序 + 并查集

  1. 首先要明白rating相同的,’ = '的两个节点是可以严格排出顺序的。
  2. 拓扑排序的序列唯一性:任何时候队列中的0度节点有且只有一个,那么序列就唯一
  3. 为什么要使用并查集维护,可以假象一下 A = B,B = C。这三个节点是可以排出C > B > A的顺序的,所以我们可以把这三个点可以看做一个节点团,相当于一个超级点。之后ABC出发或者到达的点都可以认为一个点到这个超级点,就很容易弄清楚关系。
  4. 先将相等的所有节点合并统计有多少个节点属于节点团,最后输出需要判断,再来合并不相等的情况,不相等就是从节点的根节点到根节点这样算。
    好题一道~
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 10005;
struct edge{
	int to;
	int next;
}e[maxn<<1];
struct info{
	int x,y;
	char c;
}p[maxn<<1];
int cnt,num;
int n,m;
int head[maxn];
int s[maxn];				//并查集父节点
int a[maxn];				//统计入度
queue<int>q;
inline void clear_set()
{	
	cnt = 0;num = 0;
	for(int i = 0;i < maxn;i++){
		s[i] = i;
	}
	memset(head,-1,sizeof(head));
	memset(a,0,sizeof(a));
	while(!q.empty())	q.pop();
}
inline void addedge(int x,int y)
{
	e[cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt++;
}
inline int find_set(int x)
{
	if(s[x] != x){
		s[x] = find_set(s[x]); 
	}
	return s[x];
}
inline void topsort()
{
	for(int i = 0;i < n;i++){
		if(find_set(i) == i && a[i] == 0){			//入度为0的根节点加入队列
			q.push(i);
		}
	}
	bool f = true;
	while(!q.empty()){
		if(q.size() > 1){			//序列结果不唯一 
			f = false;
		}
		int p = q.front();
		q.pop();
		for(int i = head[p];~i;i = e[i].next){
			if(--a[e[i].to] == 0){
				q.push(e[i].to);
			}
		}
		num++;					//直接拓扑的点有多少个 
	}
	if(num != n){				//凑不满n个人说明存在冲突,不是有向无环图 
		printf("CONFLICT\n");
	}
	else{					
		if(f == false){			//序列不唯一,信息不全 
			printf("UNCERTAIN\n");
		}
		else{				//序列唯一,可以确定 
			printf("OK\n");
		}
	}
}
int main()
{
	while(~scanf("%d%d",&n,&m)){
		clear_set();
		int x,y;
		for(int i = 0;i < m;i++){
			char str[5];
			scanf("%d%s%d",&x,str,&y);
			p[i].x = x;p[i].y = y;p[i].c = str[0];
			if(str[0] == '='){
				x = find_set(x);
				y = find_set(y);
				if(x != y){
					s[x] = y;			//这里相当于间接拓扑排序
					num++;				//加入节点团的点有多少个 
				}	
			}
		}
		for(int i = 0;i < m;i++){
			if(p[i].c == '=')	continue;
			x = find_set(p[i].x);			
			y = find_set(p[i].y);
			if(p[i].c == '>'){
				addedge(x,y);			//节点团到节点团的关系
				a[y]++;
			}
			else{
				addedge(y,x);
				a[x]++;
			}
		}
		topsort();
	}
	return 0;
}

愿你走出半生,归来仍是少年~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值