• bzoj 1087 状压dp


    1087: [SCOI2005]互不侵犯King

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 4130  Solved: 2390
    [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,关键就是切入点,用轮廓线的话不怎么好写,不妨逐行递推,我们用1表示这个格子放入了国王,
    从上往下递推所以不必考虑下面的国王对上面的有影响,这样的状态是非法的,注意到dp时多次用到状态之间的关系,考虑提前打表节约时间。
    由于限制了棋子的数目,相应的也要多加一维用于表示棋子数目,则显然  dp[i][j][k]+=dp[i-1][j-cnt[B]][A] ;
    dp[i][j][k]表示第i行状态为k,总共放置了j个棋子时的方案个数。
    复杂度O(N*M*2n*2n)  N<=9,复杂度合适
     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cstdlib>
     5 using namespace std;
     6 #define LL long long
     7 LL dp[10][85][1<<9],cnt[550];
     8 bool e[550][550],q[550];
     9 int N,M;
    10 bool pd(int A,int B)
    11 {
    12     bool hurt[25]; memset(hurt,0,sizeof(hurt));
    13     for(int i=0;i<9;++i)
    14        if(A&(1<<i)) hurt[i+1+5]=hurt[i-1+5]=hurt[i+5]=1;
    15     for(int i=0;i<9;++i)
    16         if( (B&(1<<i)) && hurt[i+5]) return 0;
    17     return 1;
    18 }
    19 void pre()
    20 {
    21     for(int i=0;i<(1<<9);++i){ int ss=0;
    22           for(int j=0;j<9;++j) if(i&(1<<j)) ss++;
    23     cnt[i]=ss;
    24     }
    25     for(int i=0;i<(1<<9);++i){int ok=1;
    26         for(int j=0;j<8;++j){
    27           if((i&(1<<j))&&(i&(1<<(j+1)))){ok=0;break;}
    28         }
    29         q[i]=ok;
    30     }
    31     for(int i=0;i<(1<<9);++i){
    32         for(int j=0;j<(1<<9);++j){
    33             if((!q[i])||(!q[j])) {e[i][j]=0;}
    34             else {
    35               if(pd(i,j)) {e[i][j]=1; }
    36             }
    37         }
    38     }
    39 }
    40 int main()
    41 {
    42     pre();
    43     int i,j,k;
    44     scanf("%d%d",&N,&M);
    45     dp[0][0][0]=1;
    46     for(i=1;i<=N;++i)
    47     {
    48         for(k=0;k<=M;++k)
    49         {
    50             for(int A=0;A<(1<<N);++A){
    51                 for(int B=0;B<(1<<N);++B){
    52                 if(e[A][B]&&k-cnt[B]>=0){
    53                    dp[i][k][B]+=dp[i-1][k-cnt[B]][A];
    54                 }
    55             }
    56             }
    57         }
    58     }LL ans=0;
    59     for(i=0;i<(1<<N);++i) ans+=dp[N][M][i];
    60     printf("%lld
    ",ans);
    61     return 0;
    62 }
  • 相关阅读:
    指令周期与机器周期
    MFC使用Access数据库
    函数指针的用途
    大端模式和小端模式
    Matlab信号展开
    EL表达式的11个内置对象
    JSP 4个域对象、7个动作指令、9个内置对象
    阿里巴巴java代码规范
    HDDATA基本注意事项
    SVN相关
  • 原文地址:https://www.cnblogs.com/zzqc/p/7258592.html
Copyright © 2020-2023  润新知