poj-1321

// 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!即可(布局定了,颜色如何怕不其实就是内部的排列组合了).

你可能感兴趣的:(poj,图论)