• 【状态压缩DP】【BZOJ1087】【SCOI2005】互不侵犯king


    1087: [SCOI2005]互不侵犯King

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 3135  Solved: 1825
    [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

    Solution

      本蒟蒻做的第一道状压DP,搞了一下午才A掉。

      对于棋盘中每个位置都有两种状态——放和不放,我是用1来表示放国王,用0来表示不放国王,这样就可以用一个十进制数来表示每一行放国王的某一种方案。再看一眼数据,这么小直接枚举啊!!但这枚举也是有点讲究的。

      首先我们枚举每一行所有放国王的可能的方案,我们发现如果某种方案不合法,那么(这种方案)&(这种方案>>1)一定不为零,这样就可以在枚举时排除不合法方案。接下来就是DP了。

      说是DP,其实和枚举没差了。状态转移方程为:f[i+1][t+num[x]][x]+=f[i][t][y],第一维表示第i行,第二维表示第i行及以上共放了几个国王,第三维表示第i行放国王的方案。也就是说,我们需要四重循环来花式枚举状态,枚举第 i 行,枚举当前行的方案,枚举下一行的方案,枚举放几个国王。DP完后将最后一行的所有位置的方案数相加即是正解。

      最重要的一点:

      不开long long见祖宗,十年OI一场空

      下面是AC代码:

     1 #include <cstdio>
     2 int N,K,imp;
     3 int num[1010],jdg[1010];
     4 long long f[12][512][512];
     5 void enumeration(){
     6     for(int i=0;i<=imp;++i)
     7         if(!(i&(i<<1))){
     8             int temp=i;
     9             while(temp) {num[i]+=(temp&1); temp>>=1;}
    10             jdg[i]=1; f[1][num[i]][i]=1;
    11         }
    12 }
    13 long long int DP(){ //别被这缩进吓到了...
    14     for(int i=1;i<N;++i)
    15          for(int j=0;j<=imp;++j)
    16             if(jdg[j])
    17                 for(int k=0;k<=imp;++k)
    18                     if(jdg[k])
    19                         if((!(j&k))&&(!((j>>1)&k))&&(!((j<<1)&k)))
    20                             for(int t=num[j];t+num[k]<=K;++t)
    21                                 f[i+1][t+num[k]][k]+=f[i][t][j];
    22     long long int ret=0;
    23     for(int i=0;i<=imp;++i) ret+=f[N][K][i];
    24     return ret;
    25 }
    26 int main(){
    27     scanf("%d%d",&N,&K);
    28     imp=(1<<N)-1; enumeration();
    29     printf("%lld",DP());
    30     return 0;
    31 }
  • 相关阅读:
    【Oracle】将表名与字段名连接成一行数据展示,字段名使用顿号的分隔
    【Accountancy】资产
    【FinacialKnowledge】财务报表及名词解释
    模块独立性原理
    C# this.Invoke()的作用与用法
    浅谈C#委托和事件(转载)
    C#三种定时器的实现
    一张图看懂开源许可协议,开源许可证GPL、BSD、MIT、Mozilla、Apache和LGPL的区别
    c++ comment
    C#使用StreamWriter类写入文件文件
  • 原文地址:https://www.cnblogs.com/reddest/p/5958367.html
Copyright © 2020-2023  润新知