• 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 }
  • 相关阅读:
    作业 20181030-3互评Alpha版本
    Alpha阶段事后诸葛亮会议记录
    Alpha发布用户使用报告
    20181023-2 贡献分配
    作业 20181016-1 Alpha阶段贡献分配规则
    Scrum立会报告+燃尽图(十月三十日总第二十一次)
    OC中时间函数的使用
    OC中的集合详解
    面向对象的概念详解(转)
    集中类
  • 原文地址:https://www.cnblogs.com/zzqc/p/7258592.html
Copyright © 2020-2023  润新知