题意:给出一系列排名的信息,问你是否能确定排名,还是信息有冲突,或者信息不足。
这种确定先后顺序的题目我们很自然就能想到拓扑排序,拓扑排序时就可以判出是否冲突或信息不足,冲突就是有回路,信息不足就是在确定某个是谁时有多种选择,也就是在拓扑排序时入度为0的有多个。
代码如下,代码写的比较没有条理,因为之前拓扑排序用到时dfs版的,但后面想到这道题要有唯一的拓扑序列,所以应该用入度版。转换为入度后,问题变得容易了很多。所以以后写题时还是要先考虑清楚再敲代码。
#include <iostream>
#include <string>
#include <algorithm>
#include <list>
using namespace std;
const int MAXN = 10000;
const int MAXE = 20000;
const int NIL = -1;
const int INF = 0x3f3f3f3f;
struct Edge {
int to, next;
} edge[MAXE];
struct Data {
int u, v;
} dat[MAXE];
int parent[MAXN];
bool flag;
int cnt, head[MAXN];
int indegree[MAXN];
enum Color
{
WHITE, GRAY, BLACK
} color[MAXN];
int find_parent(int x)
{
return x == parent[x] ? x : parent[x] = find_parent(parent[x]);
}
inline void Union(int a, int b) //a小b大
{
int pa = find_parent(a);
int pb = find_parent(b);
if (pa != pb)
parent[pa] = pb;
}
inline void init(int n)
{
cnt = 0;
for (int i = 0; i < n; ++i)
parent[i] = i, head[i] = edge[i].next = NIL, color[i] = WHITE, indegree[i] = 0;
}
inline void add(int u, int v)
{
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}
int vertex[MAXN];
int vertex_num;
int main(void)
{
int M, N;
int u, v;
char temp[10];
while (scanf("%d %d", &N, &M) != EOF)
{
if (N == 0)
{
puts("OK");
continue;
}
if (M == 0 && N == 1)
{
puts("OK");
continue;
}
if (M == 0)
{
puts("UNCERTAIN");
continue;
}
init(N);
int id = 0;
while (M--)
{
scanf("%d %s %d", &u, temp, &v);
if (temp[0] == '=')
{
Union(min(u, v), max(u, v));
continue;
}
if (temp[0] == '<')
swap(u, v);
dat[id].u = u;
dat[id++].v = v;
}
flag = false;
for (int i = 0; i < id; ++i)
{
u = dat[i].u;
v = dat[i].v;
//u->parent[v]
int pu = find_parent(u);
int pv = find_parent(v);
if (pu == pv)
{
flag = true; //CONFLICT
break;
}
add(pu, pv);
++indegree[pv];
}
if (flag)
{
puts("CONFLICT");
continue;
}
vertex_num = 0;
for (int i = 0; i < N; ++i)
if (parent[i] == i)
vertex[vertex_num++] = i;
bool flag2 = false;
for (int i = 0; i < vertex_num; ++i) //如果一次一个,那么n次就行
{
//找一个入度为零的点
int v = NIL;
int num = 0;
for (int j = 0; j < vertex_num; ++j)
{
u = vertex[j];
if (color[u] == WHITE && indegree[u] == 0)
{
++num;
v = u;
}
}
if (v == NIL)
{
flag = true;
break;
}
if (num > 1)
flag2 = true;
color[v] = BLACK;
for (int i = head[v]; i != NIL; i = edge[i].next)
{
u = edge[i].to;
if (color[u] == WHITE)
--indegree[u];
}
}
if (flag)
puts("CONFLICT");
else if (flag2)
puts("UNCERTAIN");
else
puts("OK");
}
return 0;
}