zoukankan      html  css  js  c++  java
  • (状压dp)NOI 2001(POJ 1185) 炮兵阵地

    司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 

    如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。 
    现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。 

    Input

    第一行包含两个由空格分割开的正整数,分别表示N和M; 
    接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。

    Output

    仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

    Sample Input

    5 4
    PHPP
    PPHH
    PPPP
    PHPP
    PHHP

    Sample Output

    6

    这两天室友和几个同系的同学都去参加了北大ACM暑期学校,借着这个光,我也跟着看北大老师的ppt和做相应题目学习了一个。

    其实这道题本身对于我还是有些挑战性的,看了ppt中讲解的思路,就豁然开朗了。

    用dp[i][j][k]记录第i行状态为j,第i-1行状态为k的最大炮兵部队摆放个数。

    dp[i][j][k] = max{dp[i-1][k][m], m = 0...1023} + Num(j), 

    在不优化时一行的状态数有2^10=1024个,可是注意到其中许多是显然不符合题意的。故需要预处理一下,将不符合的直接去掉,通过简单的DFS就可以得出总共恰好有60种情况。(注意一行什么都不填也是一种)这是本题非常重要的突破点,通过这个时间复杂度就降了下来。

    接下来还需要对第一行的情况特殊处理一下,然后就依照上述状态转移方程进行下去就可以了。

    (NOI题目ac数++ ~~)

      1 #include <iostream>
      2 #include <string>
      3 #include <algorithm>
      4 #include <cstring>
      5 #include <cstdio>
      6 #include <cmath>
      7 #include <queue>
      8 #include <set>
      9 #include <map>
     10 #include <list>
     11 #include <vector>
     12 #include <stack>
     13 #define mp make_pair
     14 //#define P make_pair
     15 #define MIN(a,b) (a>b?b:a)
     16 //#define MAX(a,b) (a>b?a:b)
     17 typedef long long ll;
     18 typedef unsigned long long ull;
     19 const int MAX=110;
     20 const int INF=1e8+5;
     21 using namespace std;
     22 //const int MOD=1e9+7;
     23 typedef pair<ll,int> pii;
     24 const double eps=0.00000001;
     25 //map<int,int>id_code,id_num;
     26 int id_code[70],id_num[70];
     27 int cnt,ge;
     28 void dfs(int code,int lo,int num)
     29 {
     30     for(int i=lo+3;i<10;i++)
     31     {
     32         dfs(code|(1<<i),i,num+1);
     33     }
     34     id_num[cnt]=num;
     35     id_code[cnt++]=code;
     36 }
     37 int dp[MAX][70][70];
     38 int n,m;
     39 char tem[15];
     40 int code;
     41 int an;
     42 bool check(int x,int y)//摆法x和地形y是否冲突
     43 {
     44     int legal=x&y;//摆上且符合地形的部分
     45     int illegal=x^legal;//摆上且不符合地形的部分
     46     if(illegal)
     47         return false;
     48     return true;
     49 }
     50 int main()
     51 {
     52     for(int i=0;i<10;i++)
     53         dfs(1<<i,i,1);
     54     memset(dp,0,sizeof(dp));
     55     id_num[cnt]=0;
     56     id_code[cnt++]=0;
     57     while(~scanf("%d%d",&n,&m))
     58     {
     59         code=0;
     60         an=0;
     61         scanf("%s",tem);
     62         for(int j=0;j<m;j++)
     63             if(tem[j]=='P')
     64                 code|=(1<<j);
     65         for(int r=0;r<cnt;r++)//特殊处理第一行
     66         {
     67             if(check(id_code[r],code))//这一行可以这么摆,与地形不冲突
     68             {
     69                 for(int p=0;p<cnt;p++)
     70                 {
     71                     if(id_code[r]&id_code[p])
     72                         continue;
     73                     dp[0][r][p]=id_num[r];//第一行的炮兵最多个数至于这一行怎么摆有关
     74                 }
     75             }
     76         }
     77         for(int i=1;i<n;i++)
     78         {
     79             code=0;
     80             scanf("%s",tem);
     81             for(int j=0;j<m;j++)
     82                 if(tem[j]=='P')
     83                     code|=(1<<j);
     84             for(int r=0;r<cnt;r++)
     85             {
     86                 if(check(id_code[r],code))//这一行可以这么摆,与地形不冲突
     87                 {
     88                     for(int p=0;p<cnt;p++)
     89                         for(int q=0;q<cnt;q++)//前两行状态
     90                         {
     91                             if((id_code[p]&id_code[q])||(id_code[r]&id_code[p])||(id_code[r]&id_code[q]))//冲突则
     92                                 continue;
     93                             dp[i][r][p]=max(dp[i][r][p],dp[i-1][p][q]+id_num[r]);
     94                         }
     95                 }
     96             }
     97         }
     98         for(int i=0;i<cnt;i++)
     99             for(int j=0;j<cnt;j++)
    100                 an=max(an,dp[n-1][i][j]);
    101         printf("%d
    ",an);
    102     }
    103     return 0;
    104 }
  • 相关阅读:
    并发编程(五):设计原理
    并发编程(四):内存语义
    并发编程(三):内存模型基础
    并发编程(二):并发机制的实现
    并发编程(一):并发编程常见问题
    Jmeter学习前提:Jmeter安装
    Python语言学习:列表常用的方法
    Python语言学习:字符串常用的方法
    Python语言学习:homework1
    Python语言学习:pyc是什么
  • 原文地址:https://www.cnblogs.com/quintessence/p/7208655.html
Copyright © 2011-2022 走看看