P1896(状态压缩)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_43475173/article/details/101689226

题目

放棋子问题,放的是国际象棋的王,不能放的是棋子的周围8格

题解

周围8格相对好判断的,先预处理,把所有可以一行存储的给找出来,判断方式是(i>>1)&i==0,并记忆存储每一种方式的棋子数,根据棋子数进行排序,方便之后的剪枝。
接着就是判断上下两行之间的关系,就是将上一行的状态,上一行前移一格,后移一格之后的三种状态与这一行的状态进行与操作只要结果不为0,就不可以

代码

#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
struct e
{
	int v,n;
}dp[1024];
int cnt,n,k;
ll qi[105][100][1024];
bool cmp(e a,e b)
{
	if(a.n==b.n) return a.v<b.v;
	else return a.n<b.n;
}
int suan(int i)
{
	int num=0;
	while(i){
		if(i&1) num++;
		i=(i>>1);
	}
	return num;
}
void init(int n)
{
	for(int i=0;i<=(1<<n)-1;i++){
		if(((i>>1)&i)==0){
			dp[++cnt].v=i;
			dp[cnt].n=suan(i);
		}
	}
	sort(dp+1,dp+cnt+1,cmp);
	/*for(int i=1;i<=cnt;i++){
		cout<<dp[i].n<<' '<<dp[i].v<<endl;
	}*/
}
int judge(int m,int n)
{
	if(n&m) return 0;
	if((n>>1)&m) return 0;
	if((n<<1)&m) return 0;
	return 1;
}
void ans(int m)
{
	for(int i=1;i<=cnt;i++){//遍历上一层的状态 
		for(int j=0;j<=k;j++){//遍历之前所有层的棋子数 
			for(int l=1;l<=cnt;l++){//遍历这一层的状态 
				if((dp[l].n+j)>k) break;
				if(judge(dp[l].v,dp[i].v)) qi[m][j+dp[l].n][dp[l].v]+=qi[m-1][j][dp[i].v];
			}
		}
	}
}
int main()
{
	cin>>n>>k;
	init(n);
	for(int i=1;i<=cnt;i++){
		qi[1][dp[i].n][dp[i].v]=1;
	}
	for(int i=2;i<=n;i++){
		ans(i);
	}
	ll num=0;
	for(int i=1;i<=cnt;i++){
		num+=qi[n][k][dp[i].v];
	}
	cout<<num<<endl;
}

猜你喜欢

转载自blog.csdn.net/qq_43475173/article/details/101689226