zoukankan      html  css  js  c++  java
  • 状压DP之互不侵犯

    题目描述

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

    输入格式

    只有一行,包含(N,K)两个数 。

    输出格式

    所得方案数。

    样例

    样例输入

    3 2

    样例输出

    16

    思路

    我们可以想到,对于当前行的影响有当前行的状态,上一行的状态(因为国王的攻击范围可以从上一行包括到这一行),以及当前行的国王数,那么我们可以用一个三维数组(f[n][k][1<<n-1]),用来代表第一维代表前(i)行((1<i<=n)),第二维代表在前(i)行放(j(0<=j<=k))个国王,第三维代表第(i)行的状态,对于f数组的初始化,只需要将(f[0][0][0])初始化为1即可;
    对于上一行的判断,我们现在用S表示当前行状态,用s表示上一行状态,那我们就有(if(S&s || (S<<1)&s || (S>>1)&s)continue),显然,我们还应该对当前行以及上一行进行判断(当前行和上一行的国王不能),显然有(if((s<<1)&s)continue),(if((S>>1)&S)continue);
    对于当前行的状态我们有(f[i][j][S]+=f[i-1][j-Q(S)][s])(Q函数用来求改状态下的国王个数,即1的个数,需要用到lowbit)。

    代码

    
    
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=(1<<9)-1;
    long long f[10][100][maxn];
    int lowbit(int x){
    	return x&-x;
    }
    int Q(int x){
    	int cnt=0;
    	for(int i=x;i;i-=lowbit(i))cnt++;
    	return cnt;
    	
    }
    int main(){
    	int n,k;
    	cin>>n>>k;
    	int maxs=1<<n;
    	f[0][0][0]=1;
    	for(int i=1;i<=n;i++){//枚举每一行
    		for(int S=0;S<maxs;S++){//枚举当前行状态
    			if((S>>1)&S)continue;
    			for(int s=0;s<maxs;s++){//枚举上一行的状态
    				if((s<<1)&s)continue;//去掉上一行排斥情况(可以无)
    				if(S&s || (S<<1)&s || (S>>1)&s)continue;//去掉当前行去上一行冲突情况
    				for(int j=Q(S);j<=k;j++){//枚举前i行的国王个数
    					f[i][j][S]+=f[i-1][j-Q(S)][s];
    				}
    			}
    		}	
    	}
    	long long ans=0;
    	for(int i=0;i<=maxs;i++){
    		ans+=f[n][k][i];
    	}
    	cout<<ans;
    
    }
    
    
    
  • 相关阅读:
    多重背包POJ1276不要求恰好装满 poj1014多重背包恰好装满
    哈理工1053完全背包
    求最小公倍数与最大公约数的函数
    Bus Pass ZOJ 2913 BFS 最大中取最小的
    POJ 3624 charm bracelet 01背包 不要求装满
    HavelHakimi定理(判断一个序列是否可图)
    z0j1008Gnome Tetravex
    ZOJ 1136 Multiple BFS 取模 POJ 1465
    01背包 擎天柱 恰好装满 zjut(浙江工业大学OJ) 1355
    zoj 2412 水田灌溉,求连通分支个数
  • 原文地址:https://www.cnblogs.com/soda-ma/p/13189741.html
Copyright © 2011-2022 走看看