[luogu 1896] [SCOI2005]互不侵犯 {状态压缩dp}

版权声明:~~~感谢支持! https://blog.csdn.net/qq_39897867/article/details/88928193

题目

https://www.luogu.org/problemnew/show/P1896


解题思路

f [ i ] [ j ] [ l ] f[i][j][l] 表示第 i i 行时, i 1 i-1 行是第 j j 个合法状态时,已经发了 l l 个王的方案数。
f [ i ] [ j ] [ l + a [ j ] ] + = f [ i 1 ] [ k ] [ l ] ( k i 2 k ) f[i][j][l+a[j]]+=f[i-1][k][l](k表示i-2行时第k个合法状态)

判断是否合法:

(!(s[j]&s[k])&&!(s[j]&(s[k]>>1))&&!(s[j]&(s[k]<<1)))
bool ant=0; 
while (x){
	if ((x&1)&&ant) return 0; 
	if (x&1) ant=1; else ant=0; 
	x>>=1;
}
return 1; 

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#define rep(i,x,y) for (register int i=x;i<=y;i++)
using namespace std; 
typedef long long ll; 
const int N=10,MAXN=(1<<9);
int n,m,s[MAXN],t[N],tot,a[MAXN]; 
ll ans,f[N][MAXN][N*N]; 
bool check(int x){
    bool ant=0; 
	while (x){
		if ((x&1)&&ant) return 0; 
		if (x&1) ant=1; else ant=0; 
		x>>=1;
	}
	return 1; 
}
int lowbit(int x){
	int ant=0; 
	while (x){
		ant+=(x&1); 
		x>>=1;
	}
	return ant; 
}
int main(){
	scanf("%d%d",&n,&m); int M=1<<n; 
	rep(i,0,M-1) if (check(i)) s[++tot]=i,a[tot]=lowbit(i),f[1][tot][a[tot]]=1; 
	rep(i,2,n) rep(j,1,tot) rep(k,1,tot) 
		if (!(s[j]&s[k])&&!(s[j]&(s[k]>>1))&&!(s[j]&(s[k]<<1)))
		rep(l,0,m-a[j]) f[i][j][l+a[j]]+=f[i-1][k][l]; 
	rep(i,1,tot) ans+=f[n][i][m]; 
	printf("%lld",ans); 
}

猜你喜欢

转载自blog.csdn.net/qq_39897867/article/details/88928193