您的位置:首页 > 其它

N骑士问题 HDU4529

2015-08-04 10:37 381 查看
最近,郑厂长对八皇后问题很感兴趣,拿着国际象棋研究了好几天,终于研究透了。兴奋之余,坐在棋盘前的他又开始无聊了。无意间,他看见眼前的棋盘上只摆了八个皇后,感觉空荡荡的,恰好又发现身边还有几个骑士,于是,他想把这些骑士也摆到棋盘上去,当然棋盘上的一个位置只能放一个棋子。因为受八皇后问题的影响,他希望自己把这些骑士摆上去之后,也要满足每2个骑士之间不能相互攻击。

  现在郑厂长想知道共有多少种摆法,你能帮助他吗?

骑士的下法:

  每步棋先横走或直走一格,然后再往外斜走一格;或者先斜走一格,最后再往外横走或竖走一格(即走“日”字)。可以越子,没有”中国象棋”的”蹩马腿”限制。

一道简单的状态压缩dp,和皇后并没有什么关系,只是摆了皇后的地方不能摆骑士。

dp[i][num][j][k] 记录四个状态:

i 代表第 i 行

num 代表前i-1行里共有num个骑士

j 代表 i-1行的状态

k 代表 i 行的状态

转移方程 dp[i][cnt+num][k][l] += dp[i-1][num][j][k];

cnt 为当前行的骑士个数 l 代表第 i 行 ,k 代表 i - 1行,j代表 i - 2 行

直接暴力写肯定会跪,刚写出来本地运行一个用例要2秒多,加上一些简单的优化就搞定了。

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int N;
int G[10];
int dp[10][11][1<<8][1<<8];
//行数(从第二行开始) 前i行骑士个数
//i-2行状态 i-1行状态

int lowbit(int k)
{
return k&(-k);
}

int cal(int n)
{
int res = 0;
while(n)
{
res++;
n -= lowbit(n);
}
return res;
}

int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(G,0,sizeof(G));
memset(dp,0,sizeof(dp));
scanf("%d",&N);
for(int i=2;i<=9;i++)
{
getchar();
for(int j=0;j<8;j++)
{
char c;
scanf("%c",&c);
if(c == '*') G[i] |= 1 << j;
}
}
dp[1][0][0][0] = 1;
int res = 0;
int tot = 1 << 8;
for(int i=2;i<=9;i++)
for(int j=0;j<tot;j++)
{// 前两行
if(G[i-2] & j) continue;
for(int k=0;k<tot;k++)
{//前一行
if(G[i-1] & k) continue;
for(int l=0;l<tot;l++)
{
if(G[i] & l) continue;
int jj = 0; //前两行对本行的影响
jj |= j << 1;
jj |= j >> 1;
jj &= tot - 1;
int kk = 0; //前一行对本行的影响
kk |= k << 2;
kk |= k >> 2;
kk &= tot - 1;
if((jj|kk) & l) continue;
int cnt = cal(l);
for(int num=0;num+cnt<=N;num++)
{
dp[i][cnt+num][k][l] += dp[i-1][num][j][k];
if(i == 9 && cnt + num == N) res += dp[i-1][num][j][k];
}
}
}
}
printf("%d\n",res);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: