• BZOJ1087: [SCOI2005]互不侵犯King(状态压缩动态规划)


    www.cnblogs.com/shaokele/


    1087: [SCOI2005]互不侵犯King##

    Time Limit: 10 Sec Memory Limit: 162 MB

    Description###

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

    Input###

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

    Output###

      方案数。

    Sample Input###

      3 2

    Sample Output###

      16

    题目地址 BZOJ1087: [SCOI2005]互不侵犯King
    题目大意:题面已经很简洁了(逃


    题解:####

      先预处理出每一层状态与下一层状态之间的关系,dp转移
      状态: (dp[i][j][k]) 表示第 (i) 层取了 (j) 个国王,这层状态为 (k)
      转移:详见标程
      c++运算优先级一定要注意啊!


    #include <cstdio>
    #define ll long long
    using namespace std;
    const int N=512;
    int n,m,all;
    int cnt[N];
    ll dp[10][100][N];
    bool fl[N],mat[N][N];
    void init(){
    	for(int i=0;i<=all;i++)
    		if((i&(i>>1))==0){            //排除同层国王的冲突情况 
    			int s=0;
    			for(int x=i;x;x>>=1)      //记录一层放国王的数量 
    				s+=x&1;
    			cnt[i]=s;fl[i]=1;
    		}
    	for(int i=0;i<=all;i++)if(fl[i])
    		for(int j=0;j<=all;j++)if(fl[j])
    			if(((i&j)==0) && ((i&(j>>1))==0) && ((j&(i>>1))==0))
    				mat[i][j]=1;          //处理状态的转移 
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	all=(1<<n)-1;
    	init();
    	for(int i=0;i<=all;i++)
    		if(fl[i])
    			dp[1][cnt[i]][i]=1;
    	for(int k=1;k<n;k++)
    		for(int i=0;i<=all;i++)if(fl[i])
    			for(int j=0;j<=all;j++)if(fl[j])               //枚举两层的状态 
    				if(mat[i][j])
    					for(int p=cnt[i];p+cnt[j]<=m;p++)      //p表示到第i层去了几个国王 
    						dp[k+1][p+cnt[j]][j]+=dp[k][p][i]; //转移 
    	ll ans=0;
    	for(int i=0;i<=all;i++)
    		ans+=dp[n][m][i];
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    CentOS 网络配置
    BUUCTF-PWN爬坑-04-pwn1_sctf_2016
    BUUCTF-PWN爬坑-03-warmup_csaw_2016
    BUUCTF-PWN爬坑-02-rip
    此博客早八百年已停止维护
    重&长剖
    FHQ Treap
    NOIP2020游记
    CSP2020 游记
    线段树套平衡树
  • 原文地址:https://www.cnblogs.com/shaokele/p/8916153.html
Copyright © 2020-2023  润新知