zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

  • 相关阅读:
    Sprinig.net 双向绑定 Bidirectional data binding and data model management 和 UpdatePanel
    Memcached是什么
    Spring.net 网络示例 codeproject
    jquery.modalbox.show 插件
    UVA 639 Don't Get Rooked
    UVA 539 The Settlers of Catan
    UVA 301 Transportation
    UVA 331 Mapping the Swaps
    UVA 216 Getting in Line
    UVA 10344 23 out of 5
  • 原文地址:https://www.cnblogs.com/liuyongliu/p/10328946.html
Copyright © 2011-2022 走看看