zoukankan      html  css  js  c++  java
  • [NOI2001] 炮兵阵地 (状压Dp经典例题)

      如果您的电脑比较优秀能在 1sec 内跑过 2^1000 的时间复杂度,不妨你可以尝试一下,其实实际时间复杂度远远少于 2^1000,作为骗分不错的选择QAQ,然后我们来分析一下正解:

      很显然此题是一题裸的状压Dp,一看数据范围就知道了,所以状态变得很显然了 f[i][j][k] 表示到第 i 层前一层是 j 上上层是 k 的最大炮兵数。

      所以转移就很显然:f[i][j][k]=max{f[i-1][k][q]+Num[j]} (Num[j] 表示第 j 行的炮兵数)

      显然时间复杂度变为了O(n*4^m*2^m),如果评测机优秀凭借你完美的常数系统应该可以卡过,但实际上真的需要枚举 2^n 个状态嘛,显然是不需要,所以我们只需要枚举一些合法状态就可以了,令人惊讶的是每一层的合法状态竟然只有60种,所以我们的时间复杂度达到了优秀的 O(n*60^3),舒服QWQ!!!

      所以我们状态变为了:f[i][j][k] 表示第 i 行前一行是合法状态 j 上上行为合法状态 k 的最大炮兵数。

      转移同上咯,自行领悟。(注意需要判断当前的合法状态是否符合当前的地形)。

      随后附上我的完美代码QWQ

      

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<cstring>
     6 using namespace std;
     7 const int MAXN=105;
     8 
     9 int Map[MAXN], Plan[MAXN], Num[MAXN], dp[MAXN][MAXN][MAXN];
    10 int N, m, cnt=0, ans;
    11 
    12 inline int get_one(int i){
    13     int sum=0;
    14     for (int x=i; x; x-=x & (-x)) sum++;
    15     return sum;
    16 }
    17 
    18 int main(){
    19     scanf("%d%d", &N, &m);
    20     for (int i=1; i<=N; i++){
    21         char st[15];
    22         scanf("%s", st+1);
    23         int len=strlen(st+1);
    24         for (int j=1; j<=len; j++) 
    25             if (st[j]=='H') Map[i]+=(1<<j-1);
    26     }      //记录当前行的地形
    27     for (int i=0; i<(1<<m); i++){
    28         if ((!((i<<1)&i)) && (!((i>>1)&i)) && (!((i<<2)&i)) && (!((i>>2)&i))){
    29             cnt++;
    30             Plan[cnt]=i;
    31             Num[cnt]=get_one(i);      //预处理当前行有几个炮兵
    32             if (!(Map[1] & Plan[cnt])) dp[1][cnt][0]=Num[cnt];      //预处理第一行的状态
    33         }
    34     }
    35     for (int i=1; i<=cnt; i++)
    36         for (int j=1; j<=cnt; j++)
    37             if ((!(Plan[i] & Plan[j])) && (!(Plan[j] & Map[2]))) 
    38                 dp[2][j][i]=max(dp[1][i][0]+Num[j], dp[2][j][i]);
    39 //预处理第二行的状态
    40     for (int i=3; i<=N; i++){
    41         for (int j=1; j<=cnt; j++)
    42             if (!(Plan[j] & Map[i])){
    43                 for (int k=1; k<=cnt; k++)
    44                     if (!(Plan[j] & Plan[k])){
    45                         for (int q=1; q<=cnt; q++)
    46                             if (!(Plan[j] & Plan[q]) && !(Plan[q] & Plan[k]))
    47                                 dp[i][j][k]=max(dp[i][j][k], dp[i-1][k][q]+Num[j]);
    48                     }
    49             }
    50     }
    51 //Dp转移
    52     for (int i=1; i<=cnt; i++)
    53         for (int j=1; j<=cnt; j++)
    54             ans=max(ans, dp[N][i][j]);
    55 //求最后一行的最值
    56     printf("%d\n", ans);
    57     return 0;
    58 }

      最后比较空的小伙伴可以去尝试一下,NOIP2016D2T3 愤怒的小鸟这一题,加油加油

      

      

  • 相关阅读:
    OSGI .Net 框架学习
    ArcEngine开发过程中的空间关系
    ITOCControl添加鼠标右键菜单
    IHookHelper的使用
    ITopologicalOperator接口调用
    GeoProcessor的使用方法
    ArcEngine内置工具条
    OSGI.NET插件方式开发你的应用
    C#在linux上运行实现
    Linux 下随机启动自己的应用 -请使用while(true) 不要Console.ReadKey()
  • 原文地址:https://www.cnblogs.com/xiannvzuimei/p/9635121.html
Copyright © 2011-2022 走看看