zoukankan      html  css  js  c++  java
  • 【状压dp】互不侵犯KING

    互不侵犯KING

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

    试题分析:状压dp,设dp[i][j][k]代表i*i的矩形放j个国王,此行状态为k的二进制的种数

                              那么容易得到转移方程:dp[i][j][k]+=dp[i-1][j-cnt[k]][p]

                              其中cnt[k]表示k在二进制下1的数量,p表示枚举的上一行的状态

    代码

    /*bzoj 1087
       wxjor 2017.06.06
    */
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<algorithm>
    //#include<cmath>
    
    using namespace std;
    const int INF = 9999999;
    #define LL long long
    
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    	return x*f;
    }
    int N,K;
    long long dp[10][100][1025];
    int cansr[1025];
    int tmp;
    int cnt[1025];
    void pre(){//预处理所有可行状态(在一行中KING互补侵犯)
    	bool flag=true;
    	for(int i=0;i<(1<<N);i++){
    		int a=0,sum=0;
    		flag=true;
    		int p=i;
    		while(i){
    			if((i&1)&&a){
    				flag=false;
    				break;
    			}
    			a=(i&1);
    			if(a) sum++;
    			i>>=1;
    		}
    		if(flag) cansr[++tmp]=p,cnt[tmp]=sum,dp[1][sum][p]=1;//计入
    		i=p;
    	}
    	return ;
    } 
    bool check(int a,int b){//判断两行中是否会侵犯
    	if((a&b)||((a>>1)&b)||((a<<1)&b)||((b<<1)&a)||((b>>1)&a)) return false;
    	return true;
    }
    long long ans;
    int main(){
    	//freopen(".in","r",stdin);
    	//freopen(".out","w",stdout);
    	N=read(),K=read();
    	pre();
    	for(int i=2;i<=N;i++){
    		for(int j=0;j<=K;j++)//一开始写成了j=1
    		    for(int k=1;k<=tmp;k++){
    		    	for(int p=1;p<=tmp;p++){
    		    		if(!check(cansr[k],cansr[p])) continue;
    		    		if(cnt[k]+cnt[p]>j) continue;//枚举的状态超出放的数量
    		    		dp[i][j][cansr[k]]+=dp[i-1][j-cnt[k]][cansr[p]];
    				}
    			}
    	}
    	for(int i=1;i<=tmp;i++) ans+=dp[N][K][cansr[i]];//求解答案
    	printf("%lld
    ",ans);
    	return 0;
    }
    //dp[i][j][k]+=dp[i-1][j-cnt(k)][k']
    

      

  • 相关阅读:
    POJ1737
    USACOTrainning.Cow Pedigrees
    USACOTrainning.Controlling Companies
    对象之间的关系有哪些,如何使用面向对象语言表达
    面向对象思想
    几种搜索引擎算法研究
    jQuery性能优化手册
    生成随机数的一个可靠算法,高质量的均匀分布的随机函数
    浮广告,兼容ie、firefox,多个漂浮不冲突,调用只需两行代码
    C#相关算法
  • 原文地址:https://www.cnblogs.com/wxjor/p/6952437.html
Copyright © 2011-2022 走看看