UVA10401(DP n皇后变种)

题目的意思就是要在n *  n的棋盘上摆放n个受伤的皇后  (受伤的皇后只能攻击那一列,以及周围8个点);

很明显可以知道,因为皇后会攻击所在列 ,所以必须每一列有一个皇后,且只能有一个.

那么输入的字符串有多长,假设长度为n 就是要在n*n棋盘摆n个皇后.

如果第一个字符是 '?'  ,则表示第一列的皇后可以让在任意行.

如果不是? ,那么第一列的皇后就要放在指定行(1 ~ F 表示1  ~ 15),

问有多少种不同的摆法.

如果字符长度为len ;

我们可以用递推.先放第一列.

f[i][j]表示第i个皇后放在第j行有几种摆法.(只考虑 i 行之前的);

如果第一个字符是 ? ,那么我们知道f[0][0] ~f[0][len] 都等于1.   如果第一个字符不是? 那么只有对应的那一个是 1;

现在我们再来放后面的.

如果第 i 个字符是 ? 那么我们可以算f[i][0] ~ f[i][len]的所有值,f[i][j]  就等与 sum ( f[i - 1][k] )(也就是把前面那一列所有的情况加起来 , 当然这里的k 和 j 必须差 1 以上 ,因为只差一行的话会互相攻击到)

如果不是 ? 也就是这一列只能放在固定一行,那么我们只能算出f[i][cur] (cur指定行) ,与上面的算法是一样 sum ( f[i - 1][k] ) ,其他的当然就是0了;

算到最后.我们把f[len - 1][k]  (k取 0 到 len - 1)加起来

就是把最后一颗皇后也摆上去,算出值,就是答案..

AC代码:


#include<stdio.h>
#include<string.h>
#define ll long long
const int N = 20;
char str[N];
ll f[N][N];
int row(char c) {
	if(c >= '0' && c <= '9')
		return c - '0' - 1;
	else
		return c - 'A' + 9;
}
int main() {
	int len;
	while(scanf("%s",str) != EOF) {
		memset(f , 0 ,sizeof(f));
		len = strlen(str);
		if(str[0] == '?') {
			for (int i = 0 ; i < len ;i++) {
				f[0][i] = 1;
			}
		}
		else
			f[0][row(str[0])] = 1;
		for (int i = 1 ; i < len ;i++) {
			if(str[i] != '?') {
				ll sum = 0;
				for (int k = 0 ; k < len ;k++) {
					if(k - row(str[i]) > 1 || row(str[i]) - k > 1)
						sum += f[i - 1][k];
				}
				f[i][row(str[i])] = sum;
				continue;
			}
			for (int j = 0 ; j < len ;j++) {
				ll sum = 0;
				for (int k = 0 ; k < len ;k++) {
					if(k - j > 1 || j - k > 1) {
						sum += f[i - 1][k];
					}
				}
				f[i][j] = sum;
			}
		}
		ll res = 0;
		for (int i = 0 ;  i < len ;i++){
			res += f[len - 1][i];
		}
		printf("%lld\n",res);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值