• P1896 [SCOI2005]互不侵犯(状压DP)


    P1896 [SCOI2005]互不侵犯

    题目描述

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

    注:数据有加强(2018/4/25)

    输入输出格式

    输入格式:

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

    输出格式:

    所得的方案数

    ::::::

    题目十分简短:观察数据范围我们可以知道:这题有庞大的状态量,所以我们就用状压DP解决问题

    dp思路:三维,第一维表示行数,第二维表示状态(二进制),第三维表示已经放了的棋子数(说实话做题做多了会有套路的,有数量限制的dp一般都要开一维表示用了的数量)

    WA点:long long型

    代码:

    /***********************************************/
    const int maxn= 1<<10;
    ll d[12][maxn][120];//当第i行为j方案时,放了z个国王,前i行的方案数 
    int can[maxn];
    
    int sum_1(ll n)//计算n二进制中1的个数
    {
    	int ans=0;
    	while(n)
    	{
    		if( (n&1) >0 ) ans++;
    		n=(n>>1);
    	}
    	return ans;
    }
    
    bool is(int n,int m)
    {
    	if( (n&m)==0 && (n&(m<<1))==0 && (n&(m>>1))==0 ) return true;
    	return false;
    }
    
    int main()
    {
    	int n,k;
    	cin>>n>>k;
    	ll mos=(1<<(n))-1;
    	for(ll i=0;i<=mos;i++)
    		if( ( i & (i<<1) ) ==0 && ( i & (i>>1) ) ==0 )
    			can[i]=1;
    	for(ll j=0;j<=mos;j++)
    		if( can[j] && sum_1(j)<=k ) d[1][j][sum_1(j)]=1;
    	for(int i=2;i<=n;i++)
    		for(ll j=0;j<=mos;j++) //暴力每种方案 
    			if( can[j] )
    				for(ll k1=0;k1<=mos;k1++) //对前一行
    					if( can[k1] && is(j,k1) ) //is:与前一行是否冲突
    						for(ll l=k;l>=sum_1(j);l--)  //此循环表示枚举第i行及之前行所有的国王数
    							d[i][j][l]+=d[i-1][k1][l-sum_1(j)];	
    	ll ans=0;
    	for(ll i=0;i<=mos;i++) ans+=d[n][i][k];
    	cout<<ans<<endl;
        return 0;
    }
    

      

  • 相关阅读:
    eclipse报错:发现了以元素 'd:skin' 开头的无效内容。此处不应含有子元素
    深入解析_Android的自定义布局
    RSA算法加密解密
    android版本
    TabHost+RadioGroup搭建基础布局
    android横竖屏控制
    一大波静态方法
    有时候
    简单的dialog菜单
    mongodb学习(三)——函数使用的小技巧
  • 原文地址:https://www.cnblogs.com/liuyongliu/p/10328946.html
Copyright © 2020-2023  润新知