您的位置:首页 > 其它

Bzoj1087 [SCOI2005]互不侵犯King

2017-02-24 12:06 288 查看
Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 3558  Solved: 2074
[Submit][Status][Discuss]

Description

  在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。

Input

  只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

Output

  方案数。

Sample Input

3 2

Sample Output

16

HINT

 

Source

 

动规 状压DP

f[行][摆放个数][状态]=方案数

仿佛状压以后的背包233

/*by SilverN*/
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
using namespace std;
const int mxn=100010;
int t[1<<10],cnt=0;
int w[1<<10];
LL f[11][90][1<<10];
int n,k;
inline bool check(int p,int r){
if(p&r)return 0;
if((p<<1)&r)return 0;
if((p>>1)&r)return 0;
return 1;
}
void init(){
int ed=(1<<n)-1;bool flag=0;
for(int i=0;i<=ed;i++){
flag=0;
for(int j=1;j<n;j++){if(((1<<j)&i) && ((1<<(j-1))&i) ){flag=1;break;}};
if(flag)continue;
t[++cnt]=i;
for(int j=0;j<n;j++)if(i&(1<<j))w[cnt]++;
}
return;
}
int main(){
int i,j,c;
scanf("%d%d",&n,&k);
init();
f[0][0][0]=1;
//  int ed=(1<<n)-1;
//  for(i=1;i<=cnt;i++)printf("%d %d\n ",t[i],w[i]);
for(i=1;i<=cnt;i++)f[1][w[i]][i]=1;
for(j=2;j<=n;j++){//行
//                  printf("ck:%d %d :%d %d\n",k1,k2,t[k1],t[k2]);
for(c=0;c<=k;c++){//摆放个数

for(int k1=1;k1<=cnt;k1++){
for(int k2=1;k2<=cnt;k2++){
if(w[k2]<=c && check(t[k1],t[k2]))
//                      printf("j:%d  c:%d\n",j,c);
//                      printf("%lld\n",f[j-1][c-w[k2]][k1]);
f[j][c][k2]+=f[j-1][c-w[k2]][k1];
//                      printf("%lld\n",f[j][c][k2]);
}
}
}
}
LL ans=0;
for(i=1;i<=cnt;i++)ans+=f
[k][i];
printf("%lld\n",ans);
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: