题目:http://poj.org/problem?id=1321
分析:题目数据量很小暴搜即可
#include <cstdio>
int n, k, tot;
char board[10][10];
void dfs(int x, int r, int u)
{
if(!x){
++tot;
return;
}
if(r >= n) return;
//try to place x on this row
for(int c = 0; c < n; ++c){
if(board[r][c] == '#' && (u & (1 << c)) == 0){
dfs(x - 1, r + 1, u | (1 << c));
}
}
//try to skip this row
if(x + r <= n) dfs(x, r + 1, u);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("__in.txt", "r", stdin);
freopen("__out.txt", "w", stdout);
#endif
while(scanf("%d%d", &n, &k), n != -1){
while(getchar() != '\n') ;
for(int i = 0; i < n; ++i) gets(board[i]);
tot = 0;
dfs(k, 0, 0);
printf("%d\n", tot);
}
return 0;
}
再看暴搜的dfs函数,很容易可以想到可行的状态总共也就k*n*2^n<=8*8*2^8=2^14,也很容易将上面的暴搜修改成记忆化DP的形式
#include <cstdio>
#include <cstring>
int n, k, f[8][8][1<<8];
char board[10][10];
int dp(int x, int r, int u)
{
if(x >= k) return 1;
if(n - r < k - x) return 0;
if(f[x][r][u] == -1){
f[x][r][u] = 0;
//try to place x on this row
for(int c = 0; c < n; ++c){
if(board[r][c] == '#' && (u & (1 << c)) == 0){
f[x][r][u] += dp(x + 1, r + 1, u | (1 << c));
}
}
//try to skip this row
f[x][r][u] += dp(x, r + 1, u);
}
return f[x][r][u];
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("__in.txt", "r", stdin);
freopen("__out.txt", "w", stdout);
#endif
while(scanf("%d%d", &n, &k), n != -1){
while(getchar() != '\n') ;
for(int i = 0; i < n; ++i){
gets(board[i]);
for(int j = 0; j < k; ++j){
memset(f[j][i], -1, (1<<n)*sizeof(int));
}
}
printf("%d\n", dp(0, 0, 0));
}
return 0;
}