zoukankan      html  css  js  c++  java
  • 【状态压缩DP】BZOJ1087-[SCOI2005]互不侵犯King

    【题目大意】

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

    【思路】

    先预处理每一行可行的状态(即单行中左右没有相邻的1),存放到usable中。

    然后预处理usable中两两之间能否相互转换,存放到map中。

    f[i][j][k]第i行,已用去j个国王,当前行状态为usable[k]的情况,四重循环暴力递推即可!

    这里用了usable按道理应该会快一些,但是和popoqqq的速度是一样的?不过这个优化应该是有效的!

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 typedef long long ll;
     7 const int MAXN=512;
     8 const int MAXK=100;
     9 const int MAXM=15;
    10 int n,m;
    11 int map[MAXN][MAXN];
    12 ll f[MAXM][MAXK][MAXN];//f[i][j][k]第i行,已用去j个国王,当前行状态为k 
    13 int usable[MAXN];
    14 int digit[MAXN];
    15  
    16 int Usable(int x)
    17 {
    18     if (x<<1&x || x>>1&x) return 0;else return 1;
    19     //不能有相邻的1 
    20 }
    21  
    22 int get_digit(int x)
    23 {
    24     int ret=0;
    25     while (x) ret+=x&1,x>>=1;
    26     return ret;
    27 }
    28  
    29 int Judge(int x,int y)
    30 {
    31     if (x&y || (x<<1)&y || (x>>1)&y) return 0;else return 1;
    32     /*不可行的情况有三种*/
    33 }
    34  
    35 void init()
    36 {
    37     memset(usable,0,sizeof(usable));
    38     memset(map,0,sizeof(map));
    39     for (int i=0;i<1<<n;i++)
    40         if (Usable(i)) usable[++usable[0]]=i;
    41     /*预处理可行的状态(左右不能有相邻的1)*/
    42     for (int i=1;i<=usable[0];i++)
    43         for (int j=1;j<=usable[0];j++)
    44         { 
    45             if (Judge(usable[i],usable[j])) map[i][j]=1;
    46         } 
    47     /*预处理可行的状态中能够转换的状态*/
    48     for (int i=1;i<=usable[0];i++) digit[i]=get_digit(usable[i]);
    49     /*预处理每一个可行状态中1的个数*/
    50 }
    51  
    52 ll dp()
    53 {
    54     memset(f,0,sizeof(f));
    55     f[0][0][1]=1;
    56     for (int i=1;i<=n;i++)
    57         for (int j=0;j<=m;j++)
    58             for (int k=1;k<=usable[0];k++)
    59                 if (digit[k]<=j)
    60                 {
    61                     for (int l=1;l<=usable[0];l++)
    62                     {
    63                         if (map[l][k] && digit[l]+digit[k]<=j) 
    64                             f[i][j][k]+=f[i-1][j-digit[k]][l];
    65                     }
    66                 }
    67     ll ret=0;
    68     for (int i=1;i<=usable[0];i++) ret+=f[n][m][i];
    69     return ret;
    70 }
    71  
    72 int main()
    73 {
    74     scanf("%d%d",&n,&m);
    75     init();
    76     cout<<dp()<<endl;
    77     return 0;   
    78 } 
  • 相关阅读:
    杭电 Problem
    杭电Problem 5053 the sum of cube 【数学公式】
    杭电 Problem 2089 不要62 【打表】
    杭电 Problem 4548 美素数【打表】
    杭电 Problem 2008 分拆素数和 【打表】
    杭电 Problem 1722 Cake 【gcd】
    杭电 Problem 2187 悼念512汶川大地震遇难同胞——老人是真饿了【贪心】
    杭电Problem 1872 稳定排序
    杭电 Problem 1753 大明A+B
    东北林业大 564 汉诺塔
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/5645057.html
Copyright © 2011-2022 走看看