小国王

题目链接:https://www.luogu.com.cn/problem/P1896

题意:

在一个NXN的棋盘上,放k个国王,求方案数
规定国王会攻击其相邻的其他国王,我们不能让国王互相攻击

思路:

状态压缩DP
考察棋盘的每一行,发现其每一列都只有 放国王 和 不放国王 2个选项,因此规定1 为放国王, 0 为不放国王
此时一行的状态可以用0~ (1<<n) 的数字来表示
为了使行内合法,相邻两个不能同时为1,用位运算判断
再来考察行间的国王合法情况,固定当前行,发现只能由其上一行国王不与其相邻的状态转移得到,也需要用到位运算判断

那么规定dp数组dp[i,j,k] :以第i行作为结尾,已经放的国王数为j,第i行状态为hefa[k]的状态

初始化dp[0,0,0]=1,意味着棋盘为空时,放的国王数为0,第0行状态为空有一种方案

最终答案为第n行所有dp状态求和

int dp[11][100][1005];
void solve(){
	int n,k;cin>>n>>k;
	vector<int>hefa;
	vector<int>num;
	for(int i=0;i<(1<<n);i++){
		if(!(i&(i>>1))){
			hefa.pb(i);
			int cnt=0;
			for(int j=0;j<n;j++){
				if(i&(1<<j))cnt++;
			}
			num.pb(cnt);
		}
	}
	
	dp[0][0][0]=1;
	int s=hefa.size();
	for(int i=1;i<=n;i++){
		for(int gw=0;gw<=k;gw++){
		for(int s1=0;s1<s;s1++){
			for(int s2=0;s2<s;s2++){
				if(gw>=num[s2]&&!(hefa[s1]&hefa[s2])&&!((hefa[s1]<<1)&hefa[s2])&&!((hefa[s1]>>1)&hefa[s2])){
					dp[i][gw][s2]+=dp[i-1][gw-num[s2]][s1];
				}
			}
		}
		}
	}
	int ans=0;
	for(int i=0;i<s;i++)ans+=dp[n][k][i];
	cout<<ans<<endl;
	
}
posted @ 2025-03-27 19:10  Marinaco  阅读(42)  评论(0)    收藏  举报
//雪花飘落效果