zoukankan      html  css  js  c++  java
  • 【SCOI2005】互不侵犯

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

    说实话,之前就一直想写状压的博客了,奈何一直没有时间搞
    互不侵犯应该是最经典的状压题目了

    状压的本质就是用一个二进制串表示当前行的状态
    所以我们枚举二进制串,判断它是否合法

    bool check(int i) {return (!(i&(i<<1)));}
    
    for(register int i=0;i<=maxn;++i)//枚举每一种状态 
    {
    	if(check(i))
    	{
    		can[++cnt]=i;
    		dp[1][cnt][getnum(i)]=1;
    	}
    }
    

    接着按行枚举,更新它的状态

    for(register int i=2;i<=n;++i)//枚举每一行 
    {
    	for(register int j=1;j<=cnt;++j)//枚举每一种状态
    	{
    		int x=can[j];//上一个状态 
    		for(register int k=1;k<=cnt;++k)
    		{
    			int y=can[k];//这一行状态
    			if(check(x,y))
    			{
    				for(register int l=0;l<=m;++l)
    					dp[i][k][getnum(y)+l]+=dp[i-1][j][l];
    			}
    		}
    	}
    }
    

    统计答案

    for(register int i=1;i<=maxn;++i)
    	ans+=dp[n][i][m];
    

    总代码:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    int n,m,cnt,can[(1<<13)];
    ll ans=0,dp[15][(1<<13)][90];//第i行,状态的下标为j,k个国王 
    
    bool check(int i)
    {
    	return (!(i&(i<<1)));
    }
    
    bool check(int x,int y)
    {
    	if(x&y) return 0;
    	if(x&(y<<1)) return 0;
    	if(x&(y>>1)) return 0;
    	return 1;
    }
    
    int getnum(int sit)
    {
    	int res=0;
    	while(sit)
    	{
    		res+=sit&1;
    		sit>>=1;
    	}
    	return res;
    }
    
    template<class T>inline void read(T &res)
    {
    	char c;T flag=1;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
    	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
    }
    
    int main()
    {
    	read(n);read(m);
    	int maxn=(1<<n)-1;
    	for(register int i=0;i<=maxn;++i)//枚举每一种状态 
    	{
    		if(check(i))
    		{
    			can[++cnt]=i;
    			dp[1][cnt][getnum(i)]=1;
    		}
    	}
    	for(register int i=2;i<=n;++i)//枚举每一行 
    	{
    		for(register int j=1;j<=cnt;++j)//枚举每一种状态
    		{
    			int x=can[j];//上一个状态 
    			for(register int k=1;k<=cnt;++k)
    			{
    				int y=can[k];//这一行状态
    				if(check(x,y))
    				{
    					for(register int l=0;l<=m;++l)
    						dp[i][k][getnum(y)+l]+=dp[i-1][j][l];
    				}
    			}
    		}
    	}
    	for(register int i=1;i<=maxn;++i)
    		ans+=dp[n][i][m];
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    Multi-Sensor, Multi- Network Positioning
    基于智能手机的3D地图导航
    2010上海世博会三维导航地图
    hdu 5452(树链刨分)
    蓝桥杯危险系数
    蓝桥杯横向打印二叉树(中序+先序遍历)
    蓝桥杯幸运数(线段树)
    hdu 5185(DP)
    2014江西理工大学C语言程序设计竞赛高级组题解
    uva 12730(期望经典)
  • 原文地址:https://www.cnblogs.com/tqr06/p/11639676.html
Copyright © 2011-2022 走看看