状态压缩DP 小国王

题目:

【题目】
在 n×n 的棋盘上放 k 个国王,国王可攻击相邻的 8 个格子,求使它们无法互相攻击的方案总数。
【输入格式】
共一行,包含两个整数 n 和 k。
1≤n≤10 ,0≤k≤n2
【输出格式】
共一行,表示方案总数,若不能够放置则输出0。
【输入样例】
3 2
【输出样例】
16

思路

由于每一个格子只有放和不放两种情况,可以用0和1表达,而此时对于0101这样表达状态可以表达成一个二进制数,即状态压缩.

#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
const int N =12;
int n,k;
vector<int >s;
vector<int >h[1<<N];//每个状态可以转移到其他状态的集合
int num[1<<N];//每个状态包含的国王数
long long f[N][N*N][1<<N];
//f(i,j,a) 表示前 i 行放了 j 个国王 ,第 i行第 a个状态的方案数 
int main(){
	cin>>n>>k;
	for(int i=0;i<(1<<n);i++){
		if(!(i&i>>1)){
			//不存在连续的 1 
			s.push_back(i);
			for(int j=0;j<n;j++){
				num[i]+=(i>>j&1);//该状态包含的国王数 
			} 
		}
	}
	for(int i=0;i<s.size();i++){
		for(int j=0;j<s.size();j++){
			int a=s[i],b=s[j];
			if(!(a&b) && !(a&b>>1) && !(a&b<<1)){
				h[i].push_back(j);//保存可以转移的状态 
			}
		}
	}
	f[0][0][0]=1;//不放国王也是一种方案 
	for(int i=1;i<=n+1;i++){
		for(int j=0;j<=k;j++){
			for(int a=0;a<s.size();a++){
				for(int b=0;b<h[a].size();b++){
					int c=num[s[a]];
					if(j>=c){//可以继续放国王 
						f[i][j][a]+=f[i-1][j-c][h[a][b]];
					}
				}
			}
		}
	}
	cout<<f[n+1][k][0]<<endl;
  return 0;
}




//  freopen("testdata.in", "r", stdin);

posted @ 2020-11-09 20:01  一个经常掉线的人  阅读(194)  评论(0)    收藏  举报