[SCOI2010]连续攻击游戏

Description

Luogu1640

BZOJ1854

Solution

方法一:

每个属性向物品连边,二分图跑匈牙利匹配。

方法二:

设每个物品的属性为((x,y))(x<y),让这个物品贡献属性(x),然后让原来贡献(x)的物品去贡献(z),其中(z)是贡献(x)的物品所能贡献的另一个属性,用并查集维护。

Code

一:

#include <cstdio>
#include <cstring>

typedef long long ll;
const int N = 1000010;
const int M = 2000010;

int matchL[N], matchR[N], hd[N], to[M], nxt[M], cnt, vis[N];

inline void adde(int x, int y) {
  to[++cnt] = y;
  nxt[cnt] = hd[x];
  hd[x] = cnt;
}

bool dfs(int x) {
  for (int i = hd[x]; i; i = nxt[i]) {
    if (vis[to[i]] != x) {
      vis[to[i]] = x;
      if (!matchL[to[i]] || dfs(matchL[to[i]])) {
        matchL[to[i]] = x;
        matchR[x] = to[i];
        return true;
      }
    }
  }
  return false;
}

int main() {
  int n;
  scanf("%d", &n);
  for (int i = 1, x, y; i <= n; ++i) {
    scanf("%d%d", &x, &y);
    if (x <= n) adde(x, i);
    if (y <= n) adde(y, i);
  }
  int i = 1;
  for (; i <= n; ++i) {
    if (matchR[i]) continue;
    if (!dfs(i)) break;
  }
  printf("%d
", i-1);
  return 0;
}

二:

#include <algorithm>
#include <cstdio>
#include <cstring>

typedef long long ll;
const int N = 1000010;
const int M = 2000010;

int fa[N], vis[N];

int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

int main() {
  int n;
  scanf("%d", &n);
  for (int i = 0; i < N; ++i) fa[i] = i;
  for (int i = 1, x, y; i <= n; ++i) {
    scanf("%d%d", &x, &y);
    x = find(x), y = find(y);
    if (x == y)
      vis[x] = 1;
    else {
      if (x > y) std::swap(x, y);
      if (vis[x])
        vis[y] = 1;
      else
        vis[x] = 1;
      fa[x] = y;
    }
  }
  for (int i = 1; i <= n; ++i)
    if (!vis[i]) {
      printf("%d
", i-1);
      return 0;
    }
  printf("%d
", n);
  return 0;
}
原文地址:https://www.cnblogs.com/wyxwyx/p/scoi2010lxgjyx.html