好题。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1811
分析:
#include <bits/stdc++.h>
using namespace std;
const int N = 10010;
vector<int> mp[N];
int vis[N];
int a[N*2], b[N*2]; // 记录输入的关系
char ch[N*2];
int n, m;
int cnt = 0; // 记录合并后剩余点的个数
int pre[N], id[N]; // id 是合并后剩余的点
int find(int x)
{
if(x == pre[x])
return x;
return pre[x] = find(pre[x]);
}
// 返回0 conflict 返回1 uncertain
int topo_sort()
{
int point = cnt; // 剩余点的个数,判断
int uncertain = 0;
priority_queue<int, vector<int>, greater<int> > que;
for(int i=0; i<cnt; i++)
{
if(vis[id[i]] == 0)
que.push(id[i]);
}
while(!que.empty())
{
if(que.size() > 1) uncertain = 1; // 如果一次队列里有两个点,说明肯定有两个点的关系不能确定,信息不全
int v = que.top(); que.pop();
point --;
for(int i=0; i<mp[v].size(); i++)
{
vis[find(mp[v][i])] --;
if(vis[find(mp[v][i])] == 0)
que.push(find(mp[v][i]));
}
}
if(point > 1) return 0; // 如果大于1 说明有环,因为有环至少剩两个点 conflict
else if(uncertain) return 1;
else return 2;
}
int main()
{
while(scanf("%d %d%*c", &n, &m) != EOF)
{
for(int i=0; i<N; i++) mp[i].clear();
for(int i=0; i<N; i++) vis[i] = 0, pre[i] = i;
for(int i=0; i<m; i++)
{
scanf("%d %c %d%*c", &a[i], &ch[i], &b[i]);
if(ch[i] == '=')
{
int fa = find(a[i]);
int fb = find(b[i]);
if(fa != fb)
pre[fa] = fb;
}
}
int conflict = 0;
for(int i=0; i<m; i++)
{
if(ch[i] == '=') continue;
int fa = find(a[i]);
int fb = find(b[i]);
if(fa == fb) // 前面输入得时候已经相等得合并了,如果除了相等还出现 > < 情况就冲突
{
conflict = 1;
break;
}
if(ch[i] == '>')
{
mp[fa].push_back(fb);
vis[fb]++;
}
else if(ch[i] == '<')
{
mp[fb].push_back(fa);
vis[fa] ++;
}
}
if(conflict) // 如果是冲突的话直接输出
{
printf("CONFLICT\n");
continue;
}
cnt = 0; // 记录合并后剩余点的个数
for(int i=0; i<n; i++) // 统计剩余的点
{
if(pre[i] == i)
id[cnt++] = i;
}
int ans = topo_sort();
if(ans == 0) printf("CONFLICT\n");
else if(ans == 1) printf("UNCERTAIN\n");
else printf("OK\n");
}
return 0;
}