• [SCOI2005]互不侵犯(状压DP)


    https://www.luogu.com.cn/problem/P1896

    题目描述

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

    注:数据有加强(2018/4/25)

    输入格式

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

    输出格式

    所得的方案数

    输入输出样例

    输入 #1

    3 2

    输出 #1

    16

    题目十分简短:观察数据范围我们可以知道:这题有庞大的状态量,所以我们就用状压DP解决问题

    dp思路:三维,第一维表示行数,第二维表示第j个可行状态,第三维表示已经放了的棋子数(这类题都有套路的,有数量限制的dp一般都要多开一维表示用了的数量)

     1 #include <bits/stdc++.h>
     2 typedef long long LL;
     3 const int INF=0x3f3f3f3f;
     4 const double eps =1e-8;
     5 const int mod=1e8;
     6 const int maxn=1e5+10;
     7 using namespace std;
     8 
     9 LL dp[10][1050][105]; //第一维表示行数,第二维表示第j个可行状态,第三维表示已经用了的棋子数
    10 int need[1050]; //第i个可行状态中1的个数 
    11 int state[1050]; //第i个可行状态是多少 
    12 int cnt;
    13 
    14 void init(int n)
    15 {
    16     for(int i=0;i<(1<<n);i++)
    17     {
    18         if(i<<1 & i) continue;
    19         state[++cnt]=i;
    20         int t=i;
    21         while(t)
    22         {
    23             need[cnt] += t%2;
    24             t>>=1; //相当于t/=2; 
    25         }
    26     }
    27 }
    28 
    29 int main()
    30 {
    31     #ifdef DEBUG
    32     freopen("sample.txt","r",stdin);
    33     #endif
    34     
    35     int n,m;
    36     scanf("%d %d",&n,&m);
    37     init(n); //初始化,别忘了 
    38     for(int i=1;i<=cnt;i++) //先处理第一行
    39     {
    40         if(need[i]<=m) dp[1][i][need[i]]=1;
    41     }
    42     for(int i=2;i<=n;i++) //处理剩下的,所以从 2 开始枚举
    43     {
    44         for(int j=1;j<=cnt;j++) //枚举状态
    45         {
    46             for(int k=1;k<=cnt;k++) //枚举上一层的状态
    47             {
    48                 if(state[j]&state[k]) continue; //上下不能相邻
    49                 if((state[k]<<1)&state[j]) continue; //本行的右上角不能有棋子 
    50                 if((state[k]>>1)&state[j]) continue; //本行的左上角也不能有棋子 
    51                 for(int g=m;g>=need[j];g--)
    52                     dp[i][j][g]+=dp[i-1][k][g-need[j]];
    53             }
    54         }
    55     }
    56     LL ans=0;
    57     for(int i=1;i<=cnt;i++)
    58         ans+=dp[n][i][m];
    59     printf("%lld
    ",ans);
    60     
    61     return 0;
    62 }

    -

  • 相关阅读:
    less-循环写法
    利用IntersectionObserver完成懒加载、加载更多
    通过is切换组件
    css3-背景渐变
    css-六边形、平行四边形、扇形实现
    vue-利用递归组件完成一个树形组件
    event loop 事件循环
    vue-组件间通信
    video 背景图平铺
    JS 事件委托
  • 原文地址:https://www.cnblogs.com/jiamian/p/12590683.html
Copyright © 2020-2023  润新知