• HDU 3442 Three Kingdoms(状态压缩 + BFS )


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

    题目大意:三国时期,刘备逃亡。给定一个最大为50*50的地图,刘备在地图中只能往4个方向走。

      地图中,A代表瞭望塔,攻击范围是2,攻击伤害是1;

      B 代表堡垒,攻击范围是3,攻击伤害是2;

      C 代表火焰,对于走在该位置上的单位造成3点伤害;

      D 代表弓箭手,攻击范围是2,攻击伤害是4;

      E 代表士兵,攻击范围是1,攻击伤害是5;

      $ 代表刘备;

      ! 代表目的地;

      # 代表障碍物

      . 代表地板

    刘备不能穿过A,B,D,E。但是可以走上C和地板。 有3条重要规则:

    1.刘备不能被相同的东西伤害2次,比如之前被瞭望塔伤害过,之后再走近瞭望塔的攻击范围时不受伤害。

    2.当刘备到达目的地,首先要计算他受到的伤害,然后结束游戏。

    3.不需要计算刘备在开始位置受到的伤害。

    判断刘备是否可以消耗最少HP,到达目的地,求出最少消耗。

    Sample Input
    1
    4 3
    .$.
    ACB
    ACB
    .!.
     
    Sample Output
    Case 1: 6
     
    分析:这道题目恶心死我了,之前用map[][],mp[][]两个数组想着方便,结果有一个地方弄错了,那个纠结啊,纠结。看来大牛喜欢长的名字也不是没有道理,起码不会跟其他名称混掉。
      题目中的攻击范围(measured by Manhattan distance)是两个点p1(x1,y1),p2(x2,y2)之间,|x1-x2|+|y1-y2|的大小
      因为A,B,C,D,E所造成的伤害分别是1,2,3,4,5,而且每种伤害最多只能受一次,所以刘备最多受到1+2+3+4+5点伤害。此时我们可以用二进制中的位数来表示伤害,比如,
    01100这个状态就表示刘备收到了C造成的3点伤害和D造成的4点伤害。
      这样做的另一个好处就是如果同一个位置受到两种或多种伤害,也可以同时表示出来,互相之间不会干扰。

     令dp[i][j][s]表示刘备在(i,j)的位置时,受伤害的状态为s时,HP的最小花费。则答案为终点位置,所有受伤状态里边HP的最小花费。

      接下来BFS

    代码如下:

      1 # include<cstdio>
      2 # include<cstring>
      3 # include<queue>
      4 # include<cmath>
      5 using namespace std;
      6 const int MAX = 55;
      7 char map[MAX][MAX];
      8 int damage[MAX][MAX];        //地图上的每一个位置刘备受到的伤害,如果为-1,表示刘备不能进入该位置
      9 int dp[MAX][MAX][1<<5];
     10 int dx[] = {1,0,0,-1};
     11 int dy[] = {0,1,-1,0};
     12 struct node{
     13     int x,y,hp;
     14 }st,u,v;
     15 
     16 int n, m, sx, sy, ex, ey;    
     17 queue<node >q;
     18 bool judge(int x,int y){
     19     if(x>=0 && x<n &&y>=0 && y<m && damage[x][y] != 1)
     20         return true;
     21     return false;
     22 }
     23 void init(){    //将原地图转化成刘备受伤害的地图
     24     int i,j,x,y,bx,by;
     25     memset(damage,0,sizeof(damage));
     26     for(i=0; i<n; i++){
     27         for(j=0; j<m; j++){    
     28             if(map[i][j] == '#')
     29                 damage[i][j] = -1;    //不可以踏入
     30             
     31             else if(map[i][j] == '$')
     32                 sx = i,        sy = j;
     33             
     34             else if(map[i][j] == '!')
     35                 ex = i,        ey = j;
     36             
     37             else if(map[i][j] == 'A'){
     38                 damage[i][j] = -1;
     39                 for(x=-2; x<3; x++){
     40                     for(y=-2; y<3; y++){
     41                         if(abs(x) + abs(y) >2) continue;
     42                         bx = i+x;
     43                         by = j+y;
     44                         if(judge(bx,by))
     45                             damage[bx][by] |= 1;
     46                     }
     47                 }
     48             }
     49             else if(map[i][j]=='B'){
     50                 damage[i][j] = -1;
     51                 for(x=-3; x<4; x++){
     52                     for(y=-3; y<4; y++){
     53                         if(abs(x) + abs(y) > 3) continue;
     54                         bx = i+x;
     55                         by = j+y;
     56                         if(judge(bx,by))
     57                             damage[bx][by] |= 1<<1;
     58                     }
     59                 }
     60             }
     61             else if(map[i][j] == 'C')
     62                 damage[i][j] |= 1<<2;
     63             
     64             else if(map[i][j] == 'D'){
     65                 damage[i][j] = -1;
     66                 for(x=-2; x<3; x++){
     67                     for(y=-2; y<3; y++){
     68                         if(abs(x) + abs(y) >2) continue;
     69                         bx = i+x;
     70                         by = j+y;
     71                         if(judge(bx,by))
     72                             damage[bx][by] |= 1<<3;
     73                     }
     74                 }
     75             }
     76             else if(map[i][j] == 'E'){
     77                 damage[i][j] = -1;
     78                 for(x=-1; x<2; x++){
     79                     for(y=-1; y<2; y++){
     80                         if(abs(x) + abs(y) >1) continue;
     81                         bx = i+x;
     82                         by = j+y;
     83                         if(judge(bx,by))
     84                             damage[bx][by] |= 1<<4;
     85                     }
     86                 }
     87             }
     88 
     89         }
     90     }
     91 }
     92 int main(){
     93     int T,cas;
     94     int i,j;
     95     scanf("%d",&T);
     96     for(cas=1; cas<=T; cas++)
     97     {
     98         scanf("%d%d",&n,&m);
     99         for(i=0; i<n; i++)
    100             scanf("%s", map[i]);
    101         init();
    102         st.x = sx;
    103         st.y = sy;
    104         st.hp = 0;
    105         memset(dp, -1, sizeof(dp));
    106         dp[st.x][st.y][0] = 0;
    107         //以上为初始化
    108         q.push(st);
    109         int a, b, c;
    110         //BFS
    111         while(!q.empty()){
    112             u = q.front();
    113             q.pop();
    114             for(i=0; i<4; i++){
    115                 b = dp[u.x][u.y][u.hp];
    116                 v.x = u.x + dx[i];
    117                 v.y = u.y + dy[i];
    118                 if(v.x>=n || v.x<0 || v.y>=m || v.y<0 ) continue;        //不在地图上
    119                 if(damage[v.x][v.y] == -1)   continue;    //不能踏入
    120 
    121                 for(j=0; j<5; j++){
    122                     a = damage[v.x][v.y] & (1<<j);    //此位置是否有给单位的伤害
    123                     c = u.hp & (1<<j);    //刘备是否已经受过了该单位的伤害
    124                     if(a!=0 && c==0)    
    125                         b += j+1;        //刘备受到伤害,伤害值为j+1
    126                 }
    127                 v.hp = u.hp | damage[v.x][v.y];    //经过该点受到的总伤害
    128                 if(dp[v.x][v.y][v.hp] == -1 || dp[v.x][v.y][v.hp] > b){
    129                     dp[v.x][v.y][v.hp] = b;    
    130                     q.push(v);
    131                 }
    132             }
    133             
    134         }
    135         int ans = -1;
    136         for(i=0; i< (1<<5); i++){    
    137             if(dp[ex][ey][i] != -1 && (dp[ex][ey][i]<ans || ans==-1))
    138                 ans = dp[ex][ey][i];
    139         }
    140         printf("Case %d: %d
    ",cas,ans);
    141     }
    142     return 0;
    143 }
  • 相关阅读:
    Understanding Unix/Linux Programming-ls指令练习二
    Understanding Unix/Linux Programming-ls指令练习一
    Understanding Unix/Linux Programming-who指令练习
    复习自控有感——20160307
    根轨迹法的校正正目标、原理和方法
    Understanding Unix/Linux Programming-cp指令练习
    树莓派交叉编译环境在Linux下的建立
    Vue最全指令大集合————VUE
    JS实现动态瀑布流及放大切换图片效果(js案例)
    JS实现自动轮播图效果(js案例)
  • 原文地址:https://www.cnblogs.com/acm-bingzi/p/3293812.html
Copyright © 2020-2023  润新知