• Hdu 4539 【状态DP】.cpp


    题意:

      一个炮兵可以攻打和他之间曼哈顿距离为2的士兵,给出你一块n*m的战场,告诉你哪些地方可以站人哪些地方不可以,问你最多可以安放多少个士兵?

      n <= 100, m <= 10

    思路:

      这道题暴力是不可以的,因为状态太多了

      可以状态DP来做,用一个数组G记录战场的限制,然后用一个数组dp[当前状态或者是前一个状态][当前状态的十进制表示][前一个状态的十进制表示]

      因为用的是G[1<<m]来表示,所以时间复杂度是n*(2^m)*(2^m)*(2^m),m最多为10,所以时间复杂度就是10*1024*1024*1024,显然这样的时间复杂度也是说不过去的。所以就用一个预处理,预处理出满足基本条件的状态,即水平距离上曼哈顿距离不为2的状态,我用bir[][2]来存预处理出来的基本状态,bir[][0]表示的是预处理的符合基本条件状态的二进制数,bir[][1]表示的是这个状态中1的个数

      

    Tips:

      因为用的是滚动数组,所以应该注意n == 1的情况

      位运算的优先级比 != 高,所以当我判断是否符合条件的时候应该直接写if(***)或者是if((***) != 0)

      不能写 == 1,因为不管是哪种位运算,出来的结果都不一定是1,只能是 != 0

      这里还有一个处理状态sta里面有多少个1的有效办法就是用lowbit(x) { return (x)&(-x)}, lowbit(x)可以提取x的最后一个1至最后一个0,这个可以利用补码原理来理解

      这样不断 i -= lowbit(i), bir[][1]++, 就可以得到相对应1的个数了

    Code:

     1 #include <stdio.h>
     2 #include <cstring>
     3 #include <bitset>
     4 #include <iostream>
     5 #include <algorithm>
     6 using namespace std;
     7 
     8 int n, m;
     9 int G[110], bir[1<<10|1][2], top;
    10 int dp[2][1<<10|1][1<<10|1];
    11 int ans;
    12 
    13 int lowbit(int x)
    14 {
    15     return (x)&(-x);
    16 }
    17 
    18 void init()
    19 {
    20     top = 0;
    21     int st = 1<<10;
    22     for (int i = 0; i < st; ++i) {
    23         if (((i>>2)&i) || ((i<<2)&i)) continue;
    24         int tmp = i;
    25         bir[top][0] = i;
    26         while (tmp) {
    27             tmp -= lowbit(tmp);
    28             bir[top][1]++;
    29         }
    30         top++;
    31     }
    32 }
    33 
    34 void DP()
    35 {
    36     int st = 1<<m;
    37     for (int i = 0; i < top && bir[i][0] < st; ++i)
    38         if ((bir[i][0]&(G[0]^(st-1))) != 0) continue; /// == 1!!!!!
    39         else ans = max(ans, bir[i][1]);
    40 
    41     if (n == 1) return;
    42 
    43     for (int i = 0; i < top && bir[i][0] < st; ++i) {
    44         for (int j = 0; j < top && bir[j][0] < st; ++j) {
    45             if (  (bir[i][0]&(G[0]^(st-1))) != 0
    46                 ||(bir[j][0]&(G[1]^(st-1))) != 0
    47                 ||((bir[i][0]<<1)&bir[j][0]) || ((bir[i][0]>>1)&bir[j][0])) continue;
    48             dp[0][j][i] = bir[i][1]+bir[j][1];
    49             ans = max(ans, dp[0][j][i]);
    50         }
    51     }
    52 // printf("___2___%d
    ", ans);
    53     int t = 1;
    54     for (int i = 2; i < n; ++i) {
    55         for (int j = 0; j < top && bir[j][0] < st; ++j) {
    56             if (bir[j][0]&(G[i-2]^(st-1))) continue;
    57             for (int k = 0; k < top && bir[k][0] < st; ++k) {
    58                 if (bir[k][0]&(G[i-1]^(st-1))) continue;
    59                 for (int l = 0; l < top && bir[l][0] < st; ++l) {
    60                     if (  ((G[i]^(st-1))&bir[l][0])
    61                         ||(bir[l][0]&bir[j][0])
    62                         ||((bir[l][0]<<1)&bir[k][0])
    63                         ||((bir[l][0]>>1)&bir[k][0])) continue;
    64                     dp[t][l][k] = max(dp[t][l][k], dp[(t+1)%2][k][j]+bir[l][1]);
    65                     ans = max(ans, dp[t][l][k]);
    66                 }
    67             }
    68         }
    69         t = (t+1)%2;
    70     }
    71 }
    72 
    73 int main()
    74 {
    75    // freopen("in.txt", "r", stdin);
    76     init();
    77 
    78     while (~scanf("%d %d", &n, &m)) {
    79         ans = -1;
    80         memset(dp, 0, sizeof(dp));
    81         for (int i = 0; i < n; ++i) {
    82             int p = 0, tmp;
    83             for (int j = 0; j < m; ++j) {
    84                 scanf("%d", &tmp);
    85                 if(tmp != 0) p |= (1<<j); ///!!!!
    86             }
    87             G[i] = p;
    88         }
    89         DP();
    90         printf("%d
    ", ans);
    91     }
    92     return 0;
    93 }
    View Code

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=4539

  • 相关阅读:
    深入理解JavaScript定时器(续)
    也谈前端基础设施建设
    Reporting Services在指定计算机上找不到报表服务器
    优化tempdb提高SQL Server的性能
    SQL 代理服务未运行。此操作需要 SQL 代理服务。 (rsSchedulerNotResponding) 获取联机帮助
    报表服务器上出现内部错误。有关详细信息,请参阅错误日志。 (rsInternalError) 获取联机帮助.找不到存储过程 'GetOneConfigurationInfo'。
    表中包含有外键时无法进行导入数据,
    SQLSTATE ODBC API(驱动程序管理器)错误
    数据库只能用机器名连接,不能用ip地址连接
    请教:不能访问通过IP访问,却可以通过机器名访问
  • 原文地址:https://www.cnblogs.com/Griselda/p/3201025.html
Copyright © 2020-2023  润新知