2 3 0 0 0 3 0 1 1 1 1 3 4 5 0 1 0 2 3 1 2 2 0 0 1 0 2 0 4 1 3 2 0 0
4 6
题意是给你n个横向的骨牌和m个纵向的骨牌,保证各自方向的骨牌不相交,问最少拿掉多少张骨牌使得所有的骨牌没有相交的情况.骨牌的长度是1.
用到了二分图的一个性质,二分图的最大独立集=所有的节点数-二分图最大匹配.
正好横向纵向两类点,如果相交就连边,然后就求个最大匹配就好了.
#include <bits/stdc++.h> using namespace std; #define maxn 2111 #define maxm 2111111 int n, m; int a[maxn][2], b[maxn][2]; struct node { int from, to, next; }edge[maxm]; int head[maxn]; int cnt; void add_edge (int from , int to) { edge[cnt].from = from, edge[cnt].to = to, edge[cnt].next = head[from], head[from] = cnt++; } bool jiao (int i, int j) { if (a[i][0] == b[j][0] && a[i][1] == b[j][1]) return 1; if (a[i][0]+1 == b[j][0] && a[i][1] == b[j][1]) return 1; if (a[i][0] == b[j][0] && a[i][1] == b[j][1]+1) return 1; if (a[i][0]+1 == b[j][0] && a[i][1] == b[j][1]+1) return 1; return 0; } int pre[maxn], vis[maxn]; bool dfs (int u) { for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (!vis[v]) { vis[v] = 1; if (pre[v] == -1 || dfs (pre[v])) { pre[v] = u; return 1; } } } return 0; } int hungry () { int ans = 0; memset (pre, -1, sizeof pre); for (int i = 1; i <= n; i++) { memset (vis, 0, sizeof vis); if (dfs (i)) ans++; } return ans; } int main () { //freopen ("in", "r", stdin); ios::sync_with_stdio (0); while (cin >> n >> m && n+m) { cnt = 0; memset (head, -1, sizeof head); for (int i = 1; i <= n; i++) { cin >> a[i][0] >> a[i][1]; } for (int j = 1+n; j <= n+m; j++) { cin >> b[j][0] >> b[j][1]; for (int i = 1; i <= n; i++) { if (jiao (i, j)) { add_edge (i, j); add_edge (j, i); } } } cout << n+m-hungry () << endl; } return 0; }