HDU-1045 Fire NetFire Net 最大团
题意:给定一个棋盘,如果在某一个点放置棋子,那么这个棋子出现的行和列都不够有其他的棋子,除非他们之间有墙相隔。现在给定一个含有墙的和空地的棋盘,问最多能够放置多少棋子。
解法:将所有为"."的点保存起来,如果两个点不在同一行且不在同一列,那么在两个点之间连一条边,否则判定两点之间是否有墙相隔,有的话连边,否则不连,最后求一个最大团即可。
代码如下:
#include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> using namespace std; int N, nd[20], idx, G[20][20]; char mp[10][10]; bool check(int a, int b) { int x1 = nd[a]/N, y1 = nd[a]%N; int x2 = nd[b]/N, y2 = nd[b]%N; if (x1 != x2 && y1 != y2) return true; if (x1 == x2) { // 如果是在同一行 for (int i = y1+1; i < y2; ++i) { if (mp[x1][i] == 'X') { return true; } } } else if (y1 == y2) { for (int i = x1+1; i < x2; ++i) { if (mp[i][y1] == 'X') { return true; } } } return false; } void build() { memset(G, 0, sizeof (G)); for (int i = 0; i < idx; ++i) { for (int j = i+1; j < idx; ++j) { G[i][j] = G[j][i] = check(i, j); } } } int ret, cnt[20], st[20]; void dfs(int x, int num) { for (int i = x+1; i < idx; ++i) { if (!G[x][i]) continue; if (cnt[i] + num <= ret) return; int flag = true; for (int j = 0; j < num; ++j) { if (!G[i][st[j]]) { flag = false; break; } } if (flag) { st[num] = i; dfs(i, num+1); } } if (num > ret) { ret = num; } } int query() { ret = 0; for (int i = idx-1; i >= 0; --i) { st[0] = i; dfs(i, 1); cnt[i] = ret; } return ret; } int main() { while (scanf("%d", &N), N) { idx = 0; for (int i = 0; i < N; ++i) { scanf("%s", mp[i]); for (int j = 0; j < N; ++j) { if (mp[i][j] == '.') { nd[idx++] = i*N+j; } } } build(); printf("%d\n", query()); } return 0; }