• BZOJ 1087(SCOI 2005) 互不侵犯


    1087: [SCOI2005]互不侵犯King

    Time Limit: 10 Sec Memory Limit: 162 MB
    Submit: 5333 Solved: 3101
    [Submit][Status][Discuss]
    Description

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

    Input

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

    Output

      方案数。

    Sample Input

    3 2
    Sample Output

    16

    —————————————————————————————-

    题解

    一看数据范围就能猜出状压dp,dp[i][k][j]表示第i行,一共放了k个棋子,状态为j的方案数。
    转移方程:
        dp[i][k][j]+=dp[i-1][k-sum[j]][k]
    sum[S]为状态S中1的个数。
    
    初值为dp[0][0][0]=1;
    

    代码

    #include<bits/stdc++.h>
    #define LL long long
    
    using namespace std;
    
    int n,K,sum[1<<10];
    LL dp[15][105][1<<10],ans;
    
    inline int update(int x){
        int cnt=0;
        for(;x;x>>=1)
            if(x&1) cnt++; 
        return cnt;
    }
    
    int main(){
        scanf("%d%d",&n,&K);
        for(register int i=0;i<1<<n;i++)
            sum[i]=update(i);
        dp[0][0][0]=1;
        for(register int i=1;i<=n;i++)
            for(register int j=0;j<1<<n;j++)
                if(!((j&(j<<1)) or (j&(j>>1)))){
                    for(register int k=0;k<1<<n;k++)
                        if(!(k&(k<<1) or k&(k>>1) or (k&j) or ((k<<1)&j)
                        or ((k<<1)&(j<<1)) or ((k>>1)&(j>>1)) or((k>>1)&j))
                        and sum[k]+sum[j]<=K){
                            for(register int o=sum[k]+sum[j];o<=K;o++)
                                dp[i][o][j]+=dp[i-1][o-sum[j]][k];
                        }
                }
        for(register int i=0;i<1<<n;i++)
            ans+=dp[n][K][i];
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    NSUserDefaults存储自定义类
    beginBackgroundTaskWithExpirationHandle
    instancetype
    #define const extern
    singleton
    报错:说改变了系统文件。解决方法
    不合法语句 self.contentView.frame.origin.x = x;
    google应用商店的解决
    笔记
    读流testDemo
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/9677085.html
Copyright © 2020-2023  润新知