BZOJ 1087 互不侵犯king

       这道题与皇后问题极像,只是两者的攻击范围不一样,同时根据题目限制可以发现,这道题数据的特殊性,棋盘很小,因此想到用状态压缩DP的方法求解。

       首先将每一行互不侵犯的可能列出来,用1、0的方式记录,之后根据要求会发现,每一行的情况受上一行的情况限制,于是从第一行进行一层层的判断。又由于国王的攻击是一个九宫格,因此难点在于两国王处于对角,则进行判断时将下一行向左移一位或向右移一位再进行判断。最后记得国王数是一定的,用一个变量记录一下。

       程序无太大的突出,但每一步写的较清晰,希望对大家有所帮助。

#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>

#define MAXN 100 //对MAXN进行赋值 。 

using namespace std;

long long int f[MAXN]/*行数*/[MAXN]/*状态*/[600]/*当前国王总数*/,i_total/*最终结果*/;
int stay[MAXN],cnt[MAXN];
 // stay用于记录每种状态压缩后的值。 cnt用于记录对应的状态中的1的个数。
int map[MAXN]/*i*/[MAXN]/*j*/; // 当上一状态为 i,下一状态为 j时,是否合法。
int i_side,i_number,i_temp=0; //边长、数量、每种状态的个数。 

void pre_dfs(int x,int y,int z)
//预处理:x 是放了几颗国王,y 是当前放的位置,z 是当前状态压缩后的值。
{
    stay[++i_temp]=z; //在stay数组中进行存储,记录目前的状压值。
    cnt[i_temp]=x; // 在cnt数组中进行存储,记录已放国王的数目 

    if(x>=(i_side+1)/2||x>=i_number)  //如果x超范围限制,则返回停止。
    {
        return;
    }
    for(int i=y+2;i<=i_side;i++) //用for循环重复所有可能,将每一种可能用递归进行记录。
    {
        pre_dfs(x+1,i,z+(1<<(i-1)));
    }

}
void pre_map()
{
     for(int i=1;i<=i_temp;i++)
    {
         for(int j=1;j<=i_temp;j++)
        {
            map[i][j]=map[j][i]=((stay[i]&stay[j])||((stay[i]>>1)&stay[j])||((stay[i]<<1)&stay[j]))?0:1;
//对 map[i][j]、 map[j][i]进行赋值,如果不移动冲突或左移冲突或右移冲突,则赋值为0,反之为1。
        }
    } 

     for(int i=1;i<=i_temp;i++)
    {
          f[1][cnt[i]][i]=1; //用f数组记录处于第一行、cnt[i]的状态下、有 i个国王时的情况。
    }
}

int main()
{
    scanf("%d%d",&i_side,&i_number);//输入边长及王的个数 

    pre_dfs(0,-1,0); //传入初始值进行深搜。
    pre_map(); // 预处理一下每种状态。 

    for(int i=2;i<=i_side;i++)
    {
          for(int j=0;j<=i_number;j++) //国王必须能全部放下。
         {
    for(int q=1;q<=i_temp;q++) //枚举上一行状态。
                {
                       if(cnt[q]>j)//状态国王数量要小于等于前 i行国王数量 j。
                       {
                               continue;
                        }
                        for(int i_number=1;i_number<=i_temp;i_number++
                       {
                  if(map[i_number][q]&&cnt[i_number]+cnt[q]<=j)
                  {
                                        f[i][j][q]+=f[i-1][j-cnt[q]][i_number];
                   }
                       }
                }
          }
    } 

    for(int i=1;i<=i_temp;i++) //计算最终值。
    {
        i_total=i_total+f[i_side][i_number][i];
    }

    printf("%lld\n",i_total); //输出结果。 

    return 0;
}

时间: 2024-10-25 04:43:17

BZOJ 1087 互不侵犯king的相关文章

BZOJ 1087 互不侵犯King (位运算)

题解:首先,这道题可以用位运算来表示每一行的状态,同八皇后的搜索方法,然后对于限制条件不相互攻击,则只需将新加入的一行左右移动与上一行相&,若是0则互不攻击,方案可行.对于每种方案,则用递推来统计,将前一排所有可以的情况全部加上即可.bit数组记录每个数字二进制位中1的个数,方便计算. if(check(j,q))f[i][j][k]+=f[i-1][q][k-bit[j]]; #include <iostream> #define rep(i,n) for (int i=0;i<

BZOJ 1087 互不侵犯的king

Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N) Output 方案数. Sample Input 3 2 Sample Output 16 首先这道题用到了名叫状压dp的算法 首先声明:这篇博客不适用于大神们!!!!! 看到互不侵犯的king这道题首先想到的

BZOJ 1087: [SCOI2005]互不侵犯King( 状压dp )

简单的状压dp... dp( x , h , s ) 表示当前第 x 行 , 用了 h 个 king , 当前行的状态为 s . 考虑转移 : dp( x , h , s ) = ∑ dp( x - 1 , h - cnt_1( s ) , s' ) ( s and s' 两行不冲突 , cnt_1( s ) 表示 s 状态用了多少个 king ) 我有各种预处理所以 code 的方程和这有点不一样 ------------------------------------------------

【状压dp】【bzoj 1087】【SCOI 2005】互不侵犯King

1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MB Submit: 1991 Solved: 1185 Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N) Output 方案数. Sa

【状压dp】互不侵犯KING

互不侵犯KING Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3866  Solved: 2264[Submit][Status][Discuss] Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N) Outp

[SCOI2005]互不侵犯King

1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 4255  Solved: 2458 [Submit][Status][Discuss] Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上 左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <=

SCOI2005互不侵犯King

1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1499  Solved: 872[Submit][Status] Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N

bzoj1087【SCOI2005】互不侵犯King

1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 2405  Solved: 1413 [Submit][Status][Discuss] Description 在N×N的棋盘里面放K个国王,使他们互不攻击.共同拥有多少种摆放方案. 国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. Input 仅仅有一行,包括两个数N.K ( 1 <=N <=9, 0 <

[Bzoj1083][SCOI2005]互不侵犯king(状压dp)

1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4595  Solved: 2664[Submit][Status][Discuss] Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K &