• 【状压DP】SCOI2005-洛谷P1896-互不侵犯 (状压例题)


    【状压DP】SCOI2005-洛谷P1896-互不侵犯 (状压例题)

    标签(空格分隔): 状压DP


    好久没写博客了,真的爽(误)

    题目:

    在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。

    输入格式
    只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

    输出格式
    所得的方案数

    输入
    3 2
    输出
    16

    思路:

    状压的入门题,做此题前建议先行做玉米地那道例题。这道题与玉米地的区别在于状态多了一维(为什么多一维:1.玉米地那道题可以理解为国王只要可以就能无限放 2.玉米地要求的是最大放置个数,这道题求得是方案数),但这就已经有点麻烦了。
    设定f[i][j][k],表示第i行状态为j时总共放了k个国王(举个例子:f[2][10100(二进制)][b[10100(二进制)]表示第2行状态为10100(第2行第3列和第5列放国王)的方案数)。

    预处理:

        int Lowbit(int x){return x & -x;};
        -----------------------------------------------------------------------------
    	int maxs=1<<n;//所有可能的二进制
        for(int i=0;i<maxs;i++){
        	if(!((i<<1)&i)){//正左正右不能放国王
        		a[++ans]=i;//a[ans]表示第ans个状态的十进制
        		for(int s=i;s;s-=Lowbit(s)){
        			b[ans]++;//表示第ans个状态放了多少个国王(1的个数)
    			}
    		}
    	}
    	for(int i=1;i<=ans;i++){//预处理第一行的状态
    		if(b[i]<=m)f[1][i][b[i]]=1;//能放就放
    	}
    

    主代码

    	for(int i=2;i<=n;i++){
    		for(int j=1;j<=ans;j++){//枚举这一行的每一个状态
    			for(int k=1;k<=ans;k++){//枚举上一行的每一个状态
    				if((a[j]&a[k])||((a[j]<<1)&a[k])||(a[k]&(a[j]>>1)))continue;//正上、左上、右上都不能放
    				//预处理的时候已经把正左正右处理了
    				for(int s=1;s<=m;s++){//枚举已有的国王数量
    					if(b[j]+s<=m)f[i][j][b[j]+s]+=f[i-1][k][s];//能放就放,再把方案数相加
    				}
    			}
    		}
    	}
    

    输出

    for(int i=1;i<=n;i++){
    		for(int j=1;j<=ans;j++){
    			sum+=f[i][j][m];
    		}
    	}
    	cout<<sum;
    

    OVER

  • 相关阅读:
    判断当天是周几
    九九乘法表
    js创建table表格
    tab切换-自动、点击、内容变换
    必须关注的25位知名JavaScript开发者
    静态路由
    dubbo
    SOA、SOAP、RPC
    【转】spring之任务调度
    Redis-cli命令最新总结【转】
  • 原文地址:https://www.cnblogs.com/614685877--aakennes/p/12733012.html
Copyright © 2020-2023  润新知