题意
就是给一个榜单严格按照rating和人品来排序,问能不能排列好,如果能排列好输出"OK",如果存在信息不全,也就是可能A > B,C > B,但是A和C无法确定大小那就信息不全输出"UNCERTAIN"。其他情况就输出"CONFLICT"。
思路
拓扑排序 + 并查集
- 首先要明白rating相同的,’ = '的两个节点是可以严格排出顺序的。
- 拓扑排序的序列唯一性:任何时候队列中的0度节点有且只有一个,那么序列就唯一
- 为什么要使用并查集维护,可以假象一下 A = B,B = C。这三个节点是可以排出C > B > A的顺序的,所以我们可以把这三个点可以看做一个节点团,相当于一个超级点。之后ABC出发或者到达的点都可以认为一个点到这个超级点,就很容易弄清楚关系。
- 先将相等的所有节点合并统计有多少个节点属于节点团,最后输出需要判断,再来合并不相等的情况,不相等就是从节点的根节点到根节点这样算。
好题一道~
#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;
}
愿你走出半生,归来仍是少年~