1087: [SCOI2005]互不侵犯King
1087: [SCOI2005]互不侵犯King
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4276 Solved: 2471
[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
/* * @Author: LyuC * @Date: 2017-09-03 21:24:43 * @Last Modified by: LyuC * @Last Modified time: 2017-09-04 21:55:56 */ /* 题意:在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上 左下右上右下八个方向上附近的各一个格子,共8个格子。 思路:类似八皇后问题,k>n的情况方案数为0,然后剩下的搜索解决 错误:这个和八皇后问题不一样,king只能攻击相邻一格,状压DP dp[i][j][k]表示第i行,j状态,已经按放k个棋子的状态 状态转移:dp[i][j][cnt=从j状态中的棋子数枚举到需要放的总的棋子数]+= dp[i-1][上一行能满足下一行是j状态的状态][cnt-j状态的棋子数] 总的来说动态规划就是抽象出来状态,就很简单了 */ #include <bits/stdc++.h> #define MAXN 15 #define MAXT 1024 #define MAXK 105 #define LL long long using namespace std; LL n,k; LL dp[MAXN][MAXT][MAXK];//dp[i][j][k]表示第i行,第j种状态时,已经放下了k个棋子的方案数 LL tol; LL cnt; LL res; bool ok(LL x,LL y){//判断上行的状态是否满足条件 for(LL i=0;i<n;i++){ if( (x&(1<<i)) ==0 ) continue; if(i==0){ if( ( y&( 1<<i ) ) !=0 || ( y&( 1<<(i+1) ) ) !=0) return false; }else if(i==n-1){ if( ( y&( 1<<i ) ) !=0 || ( y&( 1<<(i-1) ) ) !=0) return false; }else{ if( ( y&( 1<<(i-1) ) ) !=0 || ( y&( 1<<(i+1) ) ) !=0 || ( y&( 1<<i ) ) !=0) return false; } } return true; } LL judge(LL x){//判断这个状态是不是合格的 LL cur=0; for(LL i=0;i<n;i++){ if( ( x&(1<<i) ) !=0){ if(i==0){ if( ( x&( 1<< (i+1) ) )!=0){ return -1; } }else if(i==n-1){ if( ( x&(1<<(i+1)) )!=0 || ( x&(1<<(i-1)) )!=0 ){ return -1; } }else{ if( ( x&(1<<(i-1)) )!=0){ return -1; } } cur++; } } return cur; } inline void init(){ memset(dp,0,sizeof dp); res=0; } int main(){ // freopen("in.txt","r",stdin); init(); scanf("%lld%lld",&n,&k); tol=(1<<n); for(LL i=0;i<tol;i++){//初始化状态 cnt=judge(i); if(cnt!=-1){ dp[0][i][cnt]=1; } } for(LL i=1;i<n;i++){//从第二行开始递推状态 for(LL j=0;j<tol;j++){//枚举当前行的状态 cnt=judge(j); if(cnt==-1) continue; for(LL l=0;l<tol;l++){//枚举上一行的状态 if(ok(j,l)==false) continue; for(LL d=cnt;d<=k;d++){ dp[i][j][d]+=dp[i-1][l][d-cnt]; } } } } for(LL i=0;i<tol;i++){ res+=dp[n-1][i][k]; } printf("%lld\n",res); return 0; }
我每天都在努力,只是想证明我是认真的活着.