zoukankan      html  css  js  c++  java
  • 【洛谷P1896【SCOI2005】】互不侵犯King

    题目描述

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

    输入输出格式

    输入格式:

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

    输出格式:

    所得的方案数

    输入输出样例

    输入样例#1

    3 2

    输出样例#1

    16

    算法:

    状压DP

     

    分析:

    这道题乍眼一看以为是搜索,其实不然,这道题实则是一道动规的题目。

    虽然这道题目看上去和corn fields 求的东西不一样,CF那道题求的是方案数,这里求的是可行性的最大数,但是都是一堆的01串构成的(放与不放)。所以为了优化dp,这道题还是用状压dp。

     

    同样的还是要初始化所有可行的状态和第一行的信息。这个很好理解,也不多说了。

     

    但是这道题没这么简单,除了要记录上一维可行的状态之外,还要记录King的个数,将King也作为一个状态考虑。

     

    上代码:

     

     1 #include<cstdio>
     2 #include<iostream>
     3 #define C continue
     4 using namespace std;
     5 
     6 int n,k;
     7 long long dp[10][15000][80],king[15000],state[15000],tot,ans;        
     8 //dp[i][j][k]表示第i行选j状态在这一行及之前摆上k个国王的方案总数,state是状态,King是那一行的国王总数
     9 
    10 inline void init()                                //初始化
    11 {
    12     int i;
    13     tot=(1<<n)-1;
    14     for (i=0;i<=tot;i++)
    15         if (!((i<<1)&i))                            //满足提议(同行)
    16         {
    17             state[++ans]=i;
    18             int t=i;
    19             while (t)                            //记录国王个数
    20                 king[ans]+=t%2,t>>=1;            //注意是右移一位
    21         }
    22 }
    23 
    24 int main()
    25 {
    26     int i,j,p,s;
    27     scanf("%d%d",&n,&k);
    28     init();
    29     for (i=1;i<=ans;i++)                            //初始化第一行
    30         if (king[i]<=k)
    31             dp[1][i][king[i]]=1;
    32     for (i=2;i<=n;i++)                            //枚举行
    33         for (j=1;j<=ans;j++)                        //枚举这行方案
    34             for (p=1;p<=ans;p++)                //枚举上行方案
    35             {
    36                 if (state[j]&state[p])
    37                     C;
    38                 if (state[j]&(state[p]<<1))
    39                     C;
    40                 if ((state[j]<<1)&state[p])
    41                     C;
    42                 for (s=1;s<=k;s++)                //枚举国王个数
    43                 {
    44                     if (king[j]+s>k)
    45                         C;
    46                     dp[i][j][king[j]+s]+=dp[i-1][p][s];
    47                 }
    48             }
    49     tot=0;
    50     for (i=1;i<=n;i++)
    51         for (j=1;j<=ans;j++)
    52             tot+=dp[i][j][k];
    53     printf("%lld",tot);
    54     return 0;
    55 }

     

    状压dp的题主要要考虑如何优化状态,主要都是用01串来解决,其他的内容和普通dp基本是一样的。

     

    嗯,就这样了。

  • 相关阅读:
    poj 1141 Brackets Sequence (区间DP)
    算法:冒泡排序
    Learning English From Android Source Code:2 Ampersand
    泛泰A870刷4.4专用英文版非触摸CWM Recovery 6.0.4.8(三版通刷)
    Android Studio 那些事|Activity文件前标识图标显示为 j 而是 c
    HDU-4930 Fighting the Landlords 多校训练赛斗地主
    POJ 3211 Washing Clothes(01背包)
    C# winform ListView 的右键菜单的下级菜单的选项视情况禁用方法
    Android系统开发(4)——Autotools
    Android系统开发(3)——Makefile的编写
  • 原文地址:https://www.cnblogs.com/Ronald-MOK1426/p/8456798.html
Copyright © 2011-2022 走看看