zoukankan      html  css  js  c++  java
  • 1087: [SCOI2005]互不侵犯King

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 5528  Solved: 3237
    [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
     
    刚开始看上去很像八皇后问题,爆搜?实际上写了一遍爆搜发现TLE了,仔细分析可以发现状态实在是太多了,于是开始翻题解,发现是动态规划
    状压DP,以二进制压缩状态
    首先给出动规方程:

    [f[i][j][now]=sum _{last=0}^{(1<<n)-1}f[i-1][j-num[now]][last]]

    其中最大的难点是怎么判断国王位置合法,这就要用到神奇的二进制位运算了,想起了著名的约瑟夫问题,也是利用二进制得出答案

    对于当前行,设当前状态为now,!now&(now<<1),如果成立,则当前行合法。因为这就排除了两个国王相邻的可能性

    对于上下相邻的两行,用类似算法,!(now&(last<<1))  &&  !((now<<1)&last)  &&  !(now&last)

    是不是看的眼睛有点花,需要仔细分析

    为了代码简洁,实际使用continue进行排除处理

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 
     5 #define LL long long
     6 
     7 const int MAXN=1<<9;
     8 
     9 LL n,k,ans;
    10 LL num[MAXN],f[10][82][MAXN];
    11 
    12 void init()
    13 {
    14     for(int i=0;i<(1<<n);i++)
    15         if(!(i&(i<<1)))
    16         {
    17             int t=i;
    18             while(t)
    19             {
    20                 num[i]+=t&1;
    21                 t>>=1;
    22             }
    23             f[1][num[i]][i]=1;
    24         }
    25 }
    26 
    27 int main()
    28 {
    29     cin>>n>>k;
    30     init();
    31     for(int i=2;i<=n;i++)
    32         for(int j=0;j<=k;j++)
    33             for(int now=0;now<(1<<n);now++)
    34             {
    35                 if((now&(now<<1))||j<num[now]) continue;
    36                 for(int last=0;last<(1<<n);last++)
    37                 {
    38                     if(now&(last<<1)||((now<<1)&last)||(now&last)) continue;
    39                     f[i][j][now]+=f[i-1][j-num[now]][last];
    40                 }
    41             }
    42     for(int i=0;i<(1<<n);i++)
    43         ans+=f[n][k][i];
    44     cout<<ans;
    45     return 0;
    46 }
  • 相关阅读:
    QT中的定时器使用
    range()函数常和len()函数一起用于字符串索引。在这里我们要显示每一个元素及其索引值。
    range()的print 《P核》P30
    2.13 带逗号的print语句输出的元素之间自动带个空格
    Python3.x和Python2.x的区别
    print语句默认每行添加一个换行符 来自2.13
    2.12 while循环 print与计数器先后顺序对结果的影响
    函数本地绑定与全局绑定的区别
    字典映射{ :}
    《Python核心编程》P21输入数值字符串→转整型
  • 原文地址:https://www.cnblogs.com/InWILL/p/9374392.html
Copyright © 2011-2022 走看看