HDU 1811 Rank of Tetris(并查集+拓扑排序)

本文介绍了解决HDU 1811问题的方法,该问题涉及通过拓扑排序来判断一组关系是否存在矛盾或不确定性。文章详细解释了如何使用并查集压缩等价节点,并给出了完整的C++实现代码。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1811

题意:给出n个点,m个关系。

  • u > v表示u的rating高于v的。
  • u < v表示u的rating低于v的。
  • u = v表示u的rating等于v的,则最后的排序按照标号大小来排。

问给定的关系,如果存在矛盾,输出CONFLICT,如果存在不确定的,输出UNCERTAIN;都没有输出OK

思路:不需要考虑相等的时候的大小关系,把相等的点都看作一个点(用并查集来缩成一个点),然后对缩点后的图,跑一遍拓扑排序即可。
注意:当矛盾和不确定同时存在时,首先输出矛盾。

代码:

#include <stdio.h>
#include <queue>
#include <string.h>
#include <algorithm>
#include <vector>
#include <iostream>

using namespace std;

const int N = 1e4 + 10;

vector<int> g[N], h[N];
char answer[3][20] = {"OK", "CONFLICT", "UNCERTAIN"};
int in[N], f[N];
bool vis[N]; // 记录当前点是否还在缩点后的图中
int n, m;

int _find(int x) {
  return f[x] = (f[x] == x ? x : _find(f[x]));
}

int tp_sort() {
  int ct = m, res = 0;
  queue<int> q;
  for (int i = 0; i < n; i++) {
        if (in[i] == 0 && vis[i]) {
            q.push(i);
            ct--;
        }
  }
  while (!q.empty()) {
    if (q.size() > 1)
      res = 2;
    int u = q.front();
    q.pop();
    for (int i = 0; i < g[u].size(); i++) {
      int v = g[u][i];
      in[v]--;
      if (in[v] == 0) {
        q.push(v);
        ct--;
      }
    }
  }
  if (ct > 0)
    return 1;
  return res;
}

void init() {
    int ct = 0;
    for (int i = 0; i < n; i++) {
        int fi = _find(i);
        if (fi != i) {
            ct++;
            vis[i] = false;
        }
        for (int j = 0; j < h[i].size(); j++) {
            int fj = _find(h[i][j]);
            g[fi].push_back(fj);
            in[fj]++;
        }
    }
    m = n - ct;
}

int main() {
  while (scanf("%d%d", &n, &m) != EOF) {
    for (int i = 0; i < n; i++) {
      h[i].clear();
      g[i].clear();
    }
    memset(in, 0, sizeof(in));
    memset(vis, true, sizeof(vis));
    for (int i = 0; i < n; i++)
        f[i] = i;
    for (int i = 0; i < m; i++) {
      int u, v;
      char o[2];
      scanf("%d%s%d", &u, o, &v);
      int fu = _find(u);
      int fv = _find(v);
      if (o[0] == '<') {
        h[v].push_back(u);
      }
      else if (o[0] == '>') {
        h[u].push_back(v);
      }
      else if (o[0] == '=') {
        if (fu != fv)
          f[fu] = fv;
      }
      else {
        printf("Error\n");
      }
    }
    init(); // 缩点,并转换图
    int res = tp_sort();
    printf("%s\n", answer[res]);
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值