题目描述
输入N个人(编号从0到N-1),M条信息。每条信息可能有三种情况,分别是"A > B","A = B","A < B",分别表示A的Rating高于B,等于B,小于B。问根据这些信息,能否确定排名(根据Rating大小排序,Rating相同时编号大的排名靠前)。
若能够确定出这个高手榜输出"OK"。否则判断出错的原因,到底是因为信息不完全(输出"UNCERTAIN"),还是因为这些信息中包含冲突(输出"CONFLICT")。
Ps:注意,如果信息中同时包含冲突且信息不完全,就输出"CONFLICT"。
问题分析
问题一看就是拓扑排序,唯一问题就是“=”的处理,因为题目并没有要求输出排名,仅是判断排名是否确定,这样的话,优先处理“=”,将“=”连接的A、B看成同一个人,用并查集并到一个树。
例如1>2,0=1,3>1,优先处理“0=1”,令fa[1]=0,就将1用0表示,把剩下条件变成了0>2,3>0,再进行拓扑排序。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
const int MAXN = 10010;
const int MAXM = 20010;
int fa[MAXN];
int in[MAXN];
char c[MAXM];
int x[MAXM],y[MAXM];
vector<int> v[MAXN];
int n,m,num;
void init() {
for (int i=0;i<n;i++) {
fa[i] = i;
in[i] = 0;
v[i].clear();
}
num = n;
}
int find(int x) {
if (fa[x]==x) return fa[x];
return fa[x] = find(fa[x]);
}
void bfs() {
queue<int> q;
int i;
for (i=0;i<n;i++) {
if (in[i]==0 && fa[i]==i) q.push(i);
}
bool flag = true;
while (!q.empty()) {
if (q.size()>1) flag = false;
int now = q.front();
q.pop();
num--;
for (i=0;i<v[now].size();i++) {
int temp = v[now][i];
in[temp]--;
if (in[temp]==0) q.push(temp);
}
}
if (num>0) printf("CONFLICT\n");
else if (flag) printf("OK\n");
else printf("UNCERTAIN\n");
}
int main()
{
while (scanf("%d %d",&n,&m)!=EOF) {
init();
for (int i=1;i<=m;i++) {
scanf("%d %c %d",&x[i],&c[i],&y[i]);
if (c[i]=='=') {
int xx = find(x[i]);
int yy = find(y[i]);
if (xx!=yy) {
fa[yy] = xx;
num--;
}
}
}
for (int i=1;i<=m;i++) {
if (c[i]!='=') {
int xx = find(x[i]);
int yy = find(y[i]);
if (c[i]=='>') {
v[xx].push_back(yy);
in[yy]++;
}
else {
v[yy].push_back(xx);
in[xx]++;
}
}
}
bfs();
}
}