// 376K 16MS G++
#include <stdio.h>
#include <string.h>
#define MAX 10
char occupiedColumn[MAX];
char occupiedRow[MAX];
char board[MAX][MAX];
int W;
int H;
int chessNum;
#define INF 99999
int dfs(int rowId, int unDeployedChessNum) {
int combinationNum = 0;
if (unDeployedChessNum == 0) { // no chess to deploy, a valid try.
return 1;
}
// if has enterted the last row, but still have > 1 chess to deploy
if (rowId == H-1) {
if (unDeployedChessNum > 1) {
return 0; // this case is invalid, return 0;
}
}
// if all row has been checked, but still left chess, invalid case.
if (rowId == H) {
if (unDeployedChessNum > 0) {
return 0;
}
}
for (int i = 0; i < W; i++) { // check if there are invalid pos on this row.
// if this pos is #, and the colomun is not occupied yet.
if (board[rowId][i] == '#' && !occupiedColumn[i]) {
occupiedRow[rowId] = 1; // this row is occupied
occupiedColumn[i] = 1; // this coloumn is coccupied
combinationNum += dfs(rowId + 1, unDeployedChessNum - 1);
occupiedRow[rowId] = 0;
occupiedColumn[i] = 0;
}
}
// also try no deploy chess on this row.
combinationNum += dfs(rowId + 1, unDeployedChessNum);
return combinationNum;
}
void solve() {
int combinationNum = dfs(0, chessNum);
printf("%d\n", combinationNum);
}
int main() {
while(1) {
scanf("%d %d", &W, &chessNum);
if (W == -1 && chessNum == -1) {
return 0;
}
memset(occupiedColumn, 0, sizeof(occupiedColumn));
memset(occupiedRow, 0, sizeof(occupiedRow));
H = W;
for (int i = 0; i < H; i++) {
scanf("%s", board[i]);
}
solve();
}
}
八皇后的简单变种,正方形棋盘的某些区域不能再放棋子,其他的都一模一样,
离上一次写八皇后过去好久了,果然有些生疏了,不过也基本顺利写出来了:
首先要搞一个标记某列是否已经有棋子的flag数组C(不需要行数组的的flag,因为在dfs时是顺序处理行的,不用考虑行占用的情况),
然后就是dfs内部在遍历某一行有哪些位置可以放置棋子时,既要保证此列没有被占用,也要考虑是否是'#', 如果都满足,就将此列标记为被占用,
然后dfs下一行,同时要放置的棋子数量也-1,
除了选择本行放置棋子外,也可以考虑不放置,直接奔下一行dfs,只不过要放置的棋子的数量不-1,
最后,如果某一次dfs发现要放置的棋子的数量已经是0,那么这就是一个有效的方法,返回1,代表一种有效的放法。
如果已经到了第H+1行(及所有的行已经都处理过了),仍然有没有放置的棋子,那么这必然是一个无效的放法,返回0.
还可以有些优化,比如,还剩下K行可以放,但是还有 >K 的棋子没放,那么可以直接返回0了。
在每次DFS中,维护一个在此DFS节点中有效方法的总和,累加每次子DFS的返回值。
这种题一般会有更复杂的变种,如果将棋子编号,或者换成不同颜色的棋子,这种情况下组合数量会更多(虽然布局一样,但是颜色编号分布不一样),
不过却很简单,只需在上面题的基础上直接 乘以 棋子数量N的排列数 N!即可(布局定了,颜色如何怕不其实就是内部的排列组合了).