sgu 172

同一个人选择的两门课程不能在同一天考试。这个性质让我们联想到可以用二分图染色来做。可以用dfs或者bfs来染色。但是,我最后选择了用并查集来做。

设一个relation[i], 来表示节点i相对于父亲节点的关系, 当relation[i]为偶数的时候, 表示节点i和它的父亲节点是同一天的, 否则就是不同天的。然后,在普通的并查集里面,修改find方法和join方法,关键是要维护好relation字段。


#include <cstdio>
#include <algorithm>
#include <vector>

using namespace std;


bool isOdd(int x) {
  return x % 2 == 1;
}

struct UFSet {

  vector< int > father;
  vector< int > relation;

  void init(int maxV) {
    father.resize(maxV);
    int i;
    for (i = 0; i < father.size(); ++i) father[i] = -1;
    relation.resize(maxV);
    for (i = 0; i < relation.size(); ++i) relation[i] = 0;
  }

  int find(int x) {
    if (father[x] < 0) return x;
    int root = find(father[x]);
    relation[x] = simpify(relation[x] + relation[father[x]]);
    father[x] = root;
    return root;
  }

  int simpify(int x) {
    return x % 2 == 0 ? 0 : 1;
  }

  void join(int a, int b) {
    int fatherA = find(a);
    int fatherB = find(b);

    father[fatherB] = fatherA;
    relation[fatherB] = simpify(9999 - relation[a] - relation[b]);
  }

  int getRelation(int x) {
    return relation[x];
  }
};

UFSet ufs;
vector< int > ansList;

int main() {
  int N, M;
  scanf("%d %d", &N, &M);
  ufs.init(N + 1);
  int i;
  int a, b;
  bool fail = false;

  for (i = 0; i < M; ++i) {
    scanf("%d %d", &a, &b);
    if (ufs.find(a) == ufs.find(b)) {
      if (!isOdd(ufs.getRelation(a) + ufs.getRelation(b))) { fail = true; break; }
    } else {
      ufs.join(a, b);
    }
  }

  if (fail) {
    printf("no\n");
    return 0;
  }

  printf("yes\n");
  ansList.clear();
  for (i = 1; i <= N; ++i) {
    ufs.find(i);
    if (!isOdd(ufs.getRelation(i)))
      ansList.push_back(i);
  }

  printf("%d\n", ansList.size());
  for (i = 0; i < ansList.size(); ++i) {
    if (i != 0) printf(" ");
    printf("%d", ansList[i]);
  }

  printf("\n");
  return 0;
}

你可能感兴趣的:(sgu 172)