bzoj1087: [SCOI2005]互不侵犯King

裸的状压dp。。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define rep(i,n) for(int i=1;i<=n;i++)
#define clr(x,c) memset(x,c,sizeof(x))
#define ll long long 
#define REP(i,s,t) for(int i=s;i<=t;i++)
int n,m,state[1000],num[1000];
ll dp[15][1<<11][100];
bool check(int x,int y){
	if((x&(y<<1))||(x&(y>>1))||(x&y)) return false;
	return true;
}
bool pd(int x){
	if((x&(x<<1))||(x&(x>>1))) return false;
	return true;
}
int get(int x){
	int ans=0;
	while(x) {
		if(x&1) ans++;x>>=1;
	}
	return ans;
}
void init(){
	scanf("%d%d",&n,&m);
	REP(i,0,(1<<n)-1) if(pd(i)) state[++state[0]]=i,num[state[0]]=get(i);
	//rep(i,state[0]) printf("%d %d
",state[i],num[i]);
}
void work(){
	clr(dp,0);
	rep(i,state[0]) dp[1][i][num[i]]=1;
	REP(i,2,n){
		rep(j,state[0])
		  REP(k,0,m)
		    if(dp[i-1][j][k])
		      rep(t,state[0])
		        if(check(state[j],state[t])&&k+num[t]<=m)
		          dp[i][t][k+num[t]]+=dp[i-1][j][k];
	}
	ll ans=0;
	rep(i,state[0]) ans+=dp[n][i][m];
	printf("%lld
",ans);
}
int main(){
	init();work();return 0;
}

  

1087: [SCOI2005]互不侵犯King

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2779  Solved: 1638
[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

 
[Submit][Status][Discuss]
原文地址:https://www.cnblogs.com/fighting-to-the-end/p/5685800.html