题目传送门
sol:有三种情况无法构造满足条件的答案。
- 出现同一行(列)的两个'#'之间隔着一段'.'的情况,比如样例2。如果两个'#'之间隔着一段'.',那么在这一行(列)就无法放置南磁铁,因为'#'代表北磁铁可以到达,若在这一行(列)任意位置放置南磁铁,会导致这两个'#'中的至少一个北磁铁被吸到中间的'.'部分。这是违反第三条规则的。
- 每一列都出现过至少一个北磁铁,同时还有全是'.'的行出现,比如样例4,。样例4中只有一列,在这一列中出现了'#',同时第一行全都是'.',这将导致第一行无法放置南磁铁,因为在这一行的任意位置放置南磁铁都会将对应列'#'中的北磁铁吸到这一行的'.',这同样是违反第三条规则的。
- 根据第二种情况可以得出,如果每一行都出现过至少一个北磁铁,同时还有全是'.'的列出现。也是无法构造满足条件的答案的。例子就是样例4旋转90度。这会导致全是'.'的列无法放置南磁铁。
除了上述三种情况,必能构造合法答案。如果,某一行(列)中出现了'#'那就在'#'里面放置南磁铁,可以在所有'#'里面都放置一个南磁铁。如果这一行(列)中没有出现过'#',就找一个没有出现过'#'的列(行)放置南磁铁。比如样例3中第一行第五列的'#'变成了'.'那第一行的南磁铁依然放在第五列,因为第五列将没有'#'。最终需要的北磁铁的数量就是联通块的数量。
- 深度优先搜索
#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int, int> PII; const int MAXN = 1010; char mp[MAXN][MAXN]; inline int read() { int n = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -f; c = getchar(); } while (c >= '0' && c <= '9') { n = 10 * n + (c ^ '0'); c = getchar(); } return f * n; } void dfs(int i, int j) { mp[i][j] = '.'; if (mp[i + 1][j] == '#') dfs(i + 1, j); if (mp[i][j + 1] == '#') dfs(i, j + 1); if (mp[i - 1][j] == '#') dfs(i - 1, j); if (mp[i][j - 1] == '#') dfs(i, j - 1); } int main() { int n = read(), m = read(); for (int i = 1; i <= n; i++) scanf("%s", mp[i] + 1); int row = 0, col = 0; bool has = 1; // 找有多少个行出现过'#' for (int i = 1; i <= n; i++) { bool ok = 0; for (int j = 1; j <= m; j++) { if (mp[i][j] == '#') { ok = 1; break; } } row += ok; } // 找有多少个列出现过'#' for (int j = 1; j <= m; j++) { bool ok = 0; for (int i = 1; i <= n; i++) { if (mp[i][j] == '#') { ok = 1; break; } } col += ok; } for (int i = 1; i <= n; i++) { int l = -1, r = -1; for (int j = 1; j <= m; j++) { if (mp[i][j] == '#') { if (l != -1) r = j; else l = r = j; } } // 这一行没有'#'同时每一行都出现过'#',则无法构造合法解 if (l == -1) { if (col == m) has = 0; continue; } // 找是否有某行两个'#'之间出现'.' for (int j = l; j <= r; j++) { if (mp[i][j] != '#') { has = 0; break; } } } for (int j = 1; j <= m; j++) { int l = -1, r = -1; for (int i = 1; i <= n; i++) { if (mp[i][j] == '#') { if (l != -1) r = i; else l = r = i; } } // 这一列没有'#'同时每一行都出现过'#',则无法构造合法解 if (l == -1) { if (row == n) has = 0; continue; } // 找是否有某列两个'#'之间出现'.' for (int i = l; i <= r; i++) { if (mp[i][j] != '#') { has = 0; break; } } } if (has == 0) return 0 * puts("-1"); int ans = 0; // dfs找联通块 for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (mp[i][j] == '#') dfs(i, j), ans ++; } } printf("%d ", ans); return 0; }
------------------------------------------------------------分隔线------------------------------------------------------------
总结:这种题型好像做的不多,这题也算印象深刻了,考虑到了第二种无解情况居然忽略了第三种无解情况。评测机还挂了不给评测结果。这场居然urt了,不然应该就上紫了,想上个紫好难啊!!!