UVALive 6525 题目链接: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=92286#problem/A 题意: 一个n*n象棋棋盘上,有一些障碍点。 问最多放置多少个“车”,使得相邻车不会互相攻击。已知他们不能越过障碍点攻击。 思路: 二分匹配。 对于每一行或者每一列,有几个连续段就裂成几个点,如果该点合法即为’.’,则在两个裂出来的点之间可以连一条边。 源码: #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #include <iostream> #include <queue> #include <vector> #include <stack> using namespace std; #define inf (1000000000) const int MAXN = 500 + 5; int head[MAXN*MAXN], cnt; struct Edge { int u, v; int ne, flow; Edge(){} Edge(int _u, int _v, int _flow){u = _u, v = _v, flow = _flow, ne = head[_u];} }edge[MAXN * MAXN * 2]; void add_edge(int u, int v, int flow) { edge[cnt] = Edge(u, v, flow); head[u] = cnt++; edge[cnt] = Edge(v, u, 0); head[v] = cnt++; } char str[MAXN][MAXN]; int mark1[MAXN][MAXN], mark2[MAXN][MAXN]; int dx[] = {-1, 0, 1, 0}; int dy[] = {0, 1, 0, -1}; bool valid(int x, int y, int n) { for(int i = 0 ; i < 4 ; i++){ int tx = dx[i] + x; int ty = dy[i] + y; if(tx < 1 || tx > n) continue; if(ty < 1 || ty > n) continue; if(str[tx][ty] == 'X') return false; } return true; } void build_graph(int n, int s, int t) { memset(head, -1, sizeof(head)); cnt = 0; int pre1 = 0, pre2 = 0; for(int i = 1 ; i <= n ; i++){ for(int j = 1 ; j <= n ; j++){ if(mark1[i][j] != -1 && mark2[i][j] != -1) //&& valid(i, j, n)) add_edge(mark1[i][j], mark2[i][j], 1); // if(mark1[i][j] != pre1 && mark1[i][j] != -1){ // pre1 = mark1[i][j]; // add_edge(s, mark1[i][j], 1); //// pre1 = mark1[i][j]; // } // if(mark2[i][j] != pre2 && mark2[i][j] != -1){ // pre2 = mark2[i][j]; // add_edge(mark2[i][j], t, 1); //// pre2 = mark2[i][j]; // } } } } int d[MAXN*MAXN], vis[MAXN*MAXN], num[MAXN*MAXN]; queue<int>que; int BFS(int t) { memset(vis, 0, sizeof(vis)); memset(num, 0, sizeof(num)); int ans = 0; d[t] = 0, vis[t] = 1; while(!que.empty()) que.pop(); que.push(t); while(!que.empty()){ int u = que.front(); que.pop(); num[d[u]]++; ans = max(ans, d[u]); for(int now = head[u] ; now != -1 ; now = edge[now].ne){ int v = edge[now].v; if(vis[v] == 0) {d[v] = d[u] + 1, vis[v] = 1, que.push(v);} } } return ans; } int cur[MAXN*MAXN], p[MAXN*MAXN]; int Augment(int s, int t) { int flow = inf; int u = t; while(u != s){ flow = min(flow, edge[p[u]].flow); u = edge[p[u]].u; } u = t; while(u != s){ edge[p[u]].flow -= flow; edge[p[u]^1].flow += flow; u = edge[p[u]].u; } return flow; } int ISAP(int s, int t) { // printf("s = %d, t = %d\n", s, t); int up = BFS(t); for(int i = s ; i <= t ; i++) cur[i] = head[i]; int u = s; int flow = 0; while(d[s] < 2 * t + 1){ // printf("u = %d\n", u); if(u == t){ flow += Augment(s, t); u = s; } int ok = 0; for(int now = cur[u] ; now != -1 ; now = edge[now].ne){ if(edge[now].flow && d[u] == d[edge[now].v] + 1){ int v = edge[now].v; // printf("first\nv = %d\n", v); cur[u] = now; p[v] = now; u = v; ok = 1; break; } } if(!ok){ // printf("second\n"); int ts = 2 * t; for(int now = head[u] ; now != -1 ; now = edge[now].ne) if(edge[now].flow){ int v = edge[now].v; ts = min(ts, d[v]); } if(--num[d[u]] == 0) break; num[d[u] = ts + 1]++; cur[u] = head[u]; if(u != s) u = edge[p[u]].u; } } return flow; } int main() { // freopen("UVA 12668.in", "r", stdin); // freopen("UVA 12668 data2.out", "w", stdout); int n; while(scanf("%d", &n) != EOF){ int sum1 = 0, sum2 = 0; memset(mark1, 0, sizeof(mark1)); memset(mark2, 0, sizeof(mark2)); int pre = 0; for(int i = 1 ; i <= n ; i++){ scanf("%s", str[i] + 1); sum1++; for(int j = 1 ; j <= n ; j++){ if(str[i][j] == 'X' ){ sum1++; mark1[i][j] = -1; } else if(pre != sum1){ pre = sum1; mark1[i][j] = sum1; } else mark1[i][j] = sum1; // if(pre != str[i][j]){ // pre = str[i][j]; // mark1[i][j] = sum1++; // } // else{ // continue; // } } } sum2 = sum1; for(int j = 1 ; j <= n ; j++){ sum2++; for(int i = 1 ; i <= n ; i++){ if(str[i][j] == 'X' ){ sum2++; mark2[i][j] = -1; } else if(pre != sum2){ pre = sum2; mark2[i][j] = sum2; } else mark2[i][j] = sum2; } } // printf("mark1\n"); // for(int i = 1 ; i <= n ; i++){ // for(int j = 1 ; j <= n ; j++) // printf("%d ", mark1[i][j]); // printf("\n"); // } // printf("mark1\n"); // printf("mark2\n"); // for(int i = 1 ; i <= n ; i++){ // for(int j = 1 ; j <= n ; j++) // printf("%d ", mark2[i][j]); // printf("\n"); // } // printf("mark2\n"); // printf("sum1 = %d, sum2 = %d\n", sum1, sum2); int source = 0, sink = sum2 + 1; build_graph(n, source, sink); for(int i = 1 ; i <= sum1 ; i++) add_edge(0, i, 1); for(int j = sum1 + 1 ; j <= sum2 ; j++) add_edge(j, sum2 + 1, 1); int ans = ISAP(source, sink); // int temp = 0; // if(sum1 > sum2 - sum1){ // for(int i = 1 ; i <= n ; i++){ // int f = 1; // for(int j = 1 ; j <= n ; j++){ // if(mark1[i][j] == -1) {f = 1; continue;} // else if(f == 1) f = 0, temp++; // } // } // } // else{ // for(int i = 1 ; i <= n ; i++){ // int f = 1; // for(int j = 1 ; j <= n ; j++){ // if(mark2[i][j] == -1) {f = 1; continue;} // else if(f == 1) f = 0, temp++; // } // } // } // ans = temp - ans; // ans = max(sum1, sum2) - ans - n; printf("%d\n", ans); } return 0; } /* 4 .XX. .XX. XX.X .XX. */