• POJ 1185


    印象中这道题好像我曾经肝过,但是没肝出来,现在肝出来了也挺开心的

                                                                                                                                                                                                                       

    题目链接:http://poj.org/problem?id=1185

    Time Limit: 2000MS Memory Limit: 65536K

    Description

    司令部的将军们打算在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

    题解:

    感谢博文http://www.cnblogs.com/scau20110726/archive/2013/02/27/2935256.html,可以说讲的非常清晰了;

    首先,一个炮的攻击范围有两格,所以对于第i行来讲,i-1行和i-2行对它有影响,i-3行及以上的都没有影响了;

    所以我们要去求得到关于第i行的一些信息,只需要知道i-1和i-2的信息即可;

    然后考虑表示地图:

      山用1表示,空地用0表示;那么对于一行,就是一个0 or 1的串,这是个二进制数,可以状压成一个十进制数;

    再考虑表示一行上部署炮兵部队的状态:

      只考虑一行上,能不能放炮的话,状态最大达到 (1<<10) - 1 = 2^10 -1;

      但是实际上,因为炮与炮之间不能相互攻击的限制,状态数没有那么多;

      假设一个状态i,如果满足 (i&(i<<1)) == 0 && (i&(i<<2)) == 0 的话,它才是一个符合炮与炮之间相互不能攻击的状态;

      由此,我们通过枚举计算一下到底有多少状态:

    for(int i=0;i<=(1<<10)-1;i++) if( (i&(i<<1))==0 && (i&(i<<2))==0 ) cnt++;

      程序运行得到的cnt等于60,所以我们可以知道,最大的状态数不会超过60;

      由此使用一个state[]数组保存状态(依然状压成十进制数),把每次枚举出来可行的状态保存进去;

    并且值得一提的是,我们把state定义成结构体数组:

      state[i].sta:表示第i个状态时怎么样的;

      state[i].cnt:记录这个状态下,部署了多少炮兵部队;

    这样一来,方便后续操作,也不容易出错,在枚举求得所有可行状态时,也可以一并求出cnt;

    那么怎么判断炮兵部队不在山上呢?  只要state[i] & mp[r] == 0 ,就表示state[i]这个状态,可以放在r这行上,而且炮不会在山上,炮之间也不会攻击;

    那么又如何判断 i行,i-1行,i-2行的炮没有冲突呢?所以我们假设现在i行,i-1行,i-2行的炮的摆放情况分别是state[i],state[j],state[k];

    当满足 state[i] & state[j] == 0   state[i] & state[k] == 0     state[j] & state[k] == 0 条件时,三行的部署情况没有冲突;

    最后的状态转移方程,可以直接参考代码中的状态转移过程;

    AC代码:

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #define MAXN 103
      5 #define MAXM 11
      6 using namespace std;
      7 int n,m;
      8 int mp[MAXN];
      9 
     10 int state_num;
     11 struct State{
     12     int sta,cnt;
     13 }state[63];
     14 
     15 int dp[MAXN][63][63];
     16 
     17 int main()
     18 {
     19     scanf("%d%d",&n,&m);
     20 
     21     for(int i=1;i<=n;i++)
     22     {
     23         mp[i]=0;
     24         char input[12];
     25         scanf("%s",input+1);
     26         for(int j=1;j<=m;j++)
     27         {
     28             int tmp=((input[j]=='H')?1:0);
     29             mp[i]|=tmp;
     30             if(j!=m) mp[i]=mp[i]<<1;
     31         }
     32     }//二进制记录地图
     33 
     34     state_num=0;
     35     for(int i=0;i<=(1<<m)-1;i++)
     36     {
     37         if( (i&(i<<1))==0 && (i&(i<<2))==0 )
     38         {
     39             state_num++;
     40             state[state_num].sta=i;
     41 
     42             state[state_num].cnt=0;
     43             for(int tmp=i;tmp;tmp=(tmp>>1)) if(tmp&1) state[state_num].cnt++;
     44 
     45             //printf("id=%d state=%d cnt=%d
    ",state_num,state[state_num].sta,state[state_num].cnt);
     46         }
     47     }//单纯在炮与炮之间不能互相攻击的限制下,得到所有状态
     48 
     49     //状态转移过程 - st
     50     memset(dp,0,sizeof(dp));
     51 
     52     for(int i=1;i<=state_num;i++)
     53     {
     54         if(state[i].sta & mp[1]) continue;
     55         dp[1][i][1]=state[i].cnt;
     56     }//初始化dp[1][ state of row1 ][ no state ]
     57 
     58     for(int i=1;i<=state_num;i++)//枚举第2行状态
     59     {
     60         if(state[i].sta & mp[2]) continue;
     61         for(int j=1;j<=state_num;j++)//枚举第1行状态
     62         {
     63             if( (state[j].sta&mp[1]) || (state[i].sta&state[j].sta) ) continue;
     64             dp[2][i][j]=max(dp[2][i][j],dp[1][j][1]+state[i].cnt);
     65         }
     66     }//初始化dp[2][ state of row2 ][ state of row1 ]
     67 
     68     for(int r=3;r<=n;r++)
     69     {
     70 
     71         for(int i=1;i<=state_num;i++)//枚举第r行状态
     72         {
     73 
     74             if(state[i].sta & mp[r]) continue;
     75 
     76             for(int j=1;j<=state_num;j++)//枚举第r-1行状态
     77             {
     78 
     79                 if( (state[j].sta&mp[r-1]) || (state[i].sta&state[j].sta) ) continue;
     80 
     81                 for(int k=1;k<=state_num;k++)//枚举第r-2行状态
     82                 {
     83                     if(state[k].sta & mp[r-2]) continue;
     84                     if( (state[i].sta&state[k].sta) || (state[j].sta&state[k].sta) ) continue;
     85 
     86                     dp[r][i][j]=max(dp[r][i][j],dp[r-1][j][k]+state[i].cnt);
     87                 }
     88 
     89             }
     90 
     91         }
     92 
     93     }
     94     //状态转移过程 - ed
     95 
     96     int ans=0;
     97     for(int i=1;i<=state_num;i++)
     98     {
     99         for(int j=1;j<=state_num;j++)
    100         {
    101             ans=max(ans,dp[n][i][j]);
    102         }
    103     }
    104     printf("%d
    ",ans);
    105 }

                                                                                                                                                                                                                       

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

    Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)

    Problem Description
      郑厂长不是正厂长
      也不是副厂长
      他根本就不是厂长
      事实上
      他是带兵打仗的团长

      一天,郑厂长带着他的军队来到了一个n*m的平原准备布阵。
      根据以往的战斗经验,每个士兵可以攻击到并且只能攻击到与之曼哈顿距离为2的位置以及士兵本身所在的位置。当然,一个士兵不能站在另外一个士兵所能攻击到的位置,同时因为地形的原因平原上也不是每一个位置都可以安排士兵。
      现在,已知n,m 以及平原阵地的具体地形,请你帮助郑厂长计算该阵地,最多能安排多少个士兵。
     
    Input
    输入包含多组测试数据;
    每组数据的第一行包含2个整数n和m (n <= 100, m <= 10 ),之间用空格隔开;
    接下来的n行,每行m个数,表示n*m的矩形阵地,其中1表示该位置可以安排士兵,0表示该地形不允许安排士兵。
     
    Output
    请为每组数据计算并输出最多能安排的士兵数量,每组数据输出一行。
     
    Sample Input
    6 6
    0 0 0 0 0 0
    0 0 0 0 0 0
    0 0 1 1 0 0
    0 0 0 0 0 0
    0 0 0 0 0 0
    0 0 0 0 0 0
     
    Sample Output
    2
     
    题解:
    几乎完全跟上题一样,改一下其中一些判断跳过的条件即可。
     
    AC代码:
      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #define MAXN 103
      5 #define MAXM 11
      6 using namespace std;
      7 int n,m;
      8 int mp[MAXN];
      9 
     10 int state_num;
     11 struct State{
     12     int sta,cnt;
     13 }state[173];
     14 
     15 int dp[MAXN][173][173];
     16 
     17 int main()
     18 {
     19     while(scanf("%d%d",&n,&m)!=EOF)
     20     {
     21         for(int i=1,tmp;i<=n;i++)
     22         {
     23             mp[i]=0;
     24             for(int j=1;j<=m;j++)
     25             {
     26                 scanf("%d",&tmp);
     27                 tmp=!tmp;
     28                 mp[i]|=tmp;
     29                 if(j!=m) mp[i]=mp[i]<<1;
     30             }
     31         }//二进制记录地图
     32 
     33         state_num=0;
     34         for(int i=0;i<=(1<<m)-1;i++)
     35         {
     36             if( (i&(i<<2))==0 )
     37             {
     38                 state[state_num].sta=i;
     39 
     40                 state[state_num].cnt=0;
     41                 for(int tmp=i;tmp;tmp=(tmp>>1)) if(tmp&1) state[state_num].cnt++;
     42 
     43                 //printf("id=%d state=%d cnt=%d
    ",state_num,state[state_num].sta,state[state_num].cnt);
     44                 state_num++;
     45             }
     46         }//单纯在士兵与士兵之间不能互相攻击的限制下,得到所有状态
     47 
     48         //状态转移过程 - st
     49         memset(dp,0,sizeof(dp));
     50 
     51         for(int i=0;i<state_num;i++)
     52         {
     53             if(state[i].sta & mp[1]) continue;
     54             dp[1][i][0]=state[i].cnt;
     55         }//初始化dp[1][ state of row1 ][ no state ]
     56 
     57         for(int i=0;i<state_num;i++)//枚举第2行状态
     58         {
     59             if(state[i].sta & mp[2]) continue;
     60             for(int j=0;j<state_num;j++)//枚举第1行状态
     61             {
     62                 if(state[j].sta & mp[1]) continue;
     63                 if((state[j].sta<<1)&state[i].sta || (state[j].sta>>1)&state[i].sta) continue;
     64                 dp[2][i][j]=max(dp[2][i][j],dp[1][j][0]+state[i].cnt);
     65             }
     66         }//初始化dp[2][ state of row2 ][ state of row1 ]
     67 
     68         for(int r=3;r<=n;r++)
     69         {
     70 
     71             for(int i=0;i<state_num;i++)//枚举第r行状态
     72             {
     73 
     74                 if(state[i].sta & mp[r]) continue;
     75 
     76                 for(int j=0;j<state_num;j++)//枚举第r-1行状态
     77                 {
     78 
     79                     if(state[j].sta & mp[r-1]) continue;
     80                     if((state[j].sta<<1)&state[i].sta || (state[j].sta>>1)&state[i].sta) continue;
     81                     for(int k=0;k<state_num;k++)//枚举第r-2行状态
     82                     {
     83                         if(state[k].sta & mp[r-2]) continue;
     84                         if(state[i].sta & state[k].sta) continue;
     85                         if((state[k].sta<<1)&state[j].sta || (state[k].sta>>1)&state[j].sta) continue;
     86 
     87                         dp[r][i][j]=max(dp[r][i][j],dp[r-1][j][k]+state[i].cnt);
     88                     }
     89 
     90                 }
     91 
     92             }
     93 
     94         }
     95         //状态转移过程 - ed
     96 
     97         int ans=0;
     98         for(int i=0;i<state_num;i++)
     99         {
    100             for(int j=0;j<state_num;j++)
    101             {
    102                 ans=max(ans,dp[n][i][j]);
    103             }
    104         }
    105         printf("%d
    ",ans);
    106     }
    107 }
    View Code
  • 相关阅读:
    解析url
    初学react
    移动端判断用户滑动方向
    冒泡排序、快速排序、数组去重
    Angular Material主题配置
    reset()方法的使用、jq下面reset()的正确使用方法
    conts、var 、let的区别
    NLP
    mybatis的执行流程
    PHP递归算法示例:打印无限级数组元素的值
  • 原文地址:https://www.cnblogs.com/dilthey/p/7604432.html
Copyright © 2020-2023  润新知