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']
    

      

  • 相关阅读:
    微信二维码 场景二维码 用于推送事件,关注等 注册用户 ,经过测试
    简单的 Helper 封装 -- CookieHelper
    简单的 Helper 封装 -- SecurityHelper 安全助手:封装加密算法(MD5、SHA、HMAC、DES、RSA)
    Java反射机制
    Windows Azure Web Site (13) Azure Web Site备份
    Windows Azure Virtual Machine (1) IaaS用户手册
    Windows Azure Web Site (1) 用户手册
    Windows Azure Web Site (12) Azure Web Site配置文件
    Windows Azure Web Site (11) 使用源代码管理器管理Azure Web Site
    Windows Azure Web Site (10) Web Site测试环境
  • 原文地址:https://www.cnblogs.com/wxjor/p/6952437.html
Copyright © 2011-2022 走看看