• 计蒜客模拟赛D2T3 蒜头君救人:用bfs转移状压dp


    题目链接:https://nanti.jisuanke.com/t/16444

    题意:

      蒜头君是一个乐于助人的好孩子,这天他所在的乡村发生了洪水,有多名村民被困于孤岛上,于是蒜头君决定去背他们离开困境,假设蒜头君所在的村子是n*m的网格,网格中.号代表平地,#号代表该地已被洪水淹没,A、B……等大写字母表示该地有村民被困,s代表蒜头君的起点,t代表蒜头君的终点。

      蒜头君的初始速度为 k秒一格,他每次可以向上下左右4个方向中的一个移动1格。在背上一个村民后,他的速度可能会降低,也可能会加快,但他的速度不能快于1秒每格,那么蒜头君想知道,他最快需要多长时间将所有村民救出?

      注意:不能在终点以外的地方放下村民;可以同时背多个村民。

    题解:

      用dp[state][x][y]表示现在在(x , y)这个点,村民的状态为state。state是一个三进制数,每一位对应一个村民,0表示村民还在原地,1表示正在背着这个村民,2表示这个村民已经到达终点。

      显然,应该先枚举村民状态state,再枚举当前位置(x , y)。但本题和一般的网格dp不同,起点并不一定在左上角(1 , 1)处,而且并不是只能走右和下两个方向,因此本题需要从起点开始bfs,对于每一个被更新dp值的状态,都需要加入队列中。

      下面考虑如何转移。

      如果当前地点为'.'(平地),那么state不变,向上下左右四个方向转移(不能是'#'),dp[state][...][...](上下左右) = min(dp[state][...][...] , dp[state][x][y] + cal_spd(state)),cal_spd(state)计算的是在当前状态时自己的速度。

      如果当前地点为大写字母(有村民要救),并且当前state中这个村民还在原地,那么可以背上这个村民,dp[state_pick][x][y] = min(dp[state_pick][x][y] , dp[state][x][y]),state_pick为在当前state下再背上这个村民时的状态。

      如果现在在终点t,很明显只有两种选择,一种是放下所有会让我减速的村民(能让我加速的村民肯定要一直背到底),一种是放下全部的村民(结束救人)。两种转移后的状态分别为state_part和state_all,那么dp[state_part][x][y] = min(dp[state_part][x][y] , dp[state][x][y]),dp[state_all][x][y] = min(dp[state_all][x][y] , dp[state][x][y])。

    AC Code:

      1 #include <iostream>
      2 #include <stdio.h>
      3 #include <string.h>
      4 #include <ctype.h>
      5 #include <queue>
      6 #define MAX_N 15
      7 #define MAX_S 60000
      8 #define MAX_A 30
      9 #define INF 10000000
     10 
     11 using namespace std;
     12 
     13 const int POW[]={1,3,9,27,81,243,729,2187,6561,19683,59049,177147,531441};
     14 
     15 struct Coor
     16 {
     17     int x;
     18     int y;
     19     Coor(int _x,int _y)
     20     {
     21         x=_x;
     22         y=_y;
     23     }
     24     Coor(){}
     25 };
     26 
     27 struct sta
     28 {
     29     int state;
     30     int x;
     31     int y;
     32     sta(int _state,int _x,int _y)
     33     {
     34         state=_state;
     35         x=_x;
     36         y=_y;
     37     }
     38     sta(){}
     39 };
     40 
     41 int n,m,k;
     42 int cnt=0;
     43 int spd[MAX_A];
     44 int dp[MAX_S][MAX_N][MAX_N];
     45 char c[MAX_N][MAX_N];
     46 bool vis[MAX_S][MAX_N][MAX_N];
     47 Coor start;
     48 Coor over;
     49 queue<sta> q;
     50 
     51 inline int update(int &v,int k,int a)
     52 {
     53     return v=v-((v/POW[k])%3)*POW[k]+a*POW[k];
     54 }
     55 
     56 inline int query(int v,int k)
     57 {
     58     return (v/POW[k])%3;
     59 }
     60 
     61 void read()
     62 {
     63     cin>>n>>m>>k;
     64     for(int i=1;i<=n;i++)
     65     {
     66         for(int j=1;j<=m;j++)
     67         {
     68             cin>>c[i][j];
     69             if(c[i][j]=='s') start=Coor(i,j);
     70             if(c[i][j]=='t') over=Coor(i,j);
     71             if(isupper(c[i][j])) cnt++;
     72         }
     73     }
     74     for(int i=0;i<cnt;i++)
     75     {
     76         char ch;
     77         int speed;
     78         cin>>ch>>speed;
     79         spd[i]=speed;
     80     }
     81 }
     82 
     83 int cal_spd(int state)
     84 {
     85     int sum=k;
     86     for(int i=0;i<cnt;i++)
     87     {
     88         int val=query(state,i);
     89         if(val==1) sum+=spd[i];
     90     }
     91     return sum>=1?sum:1;
     92 }
     93 
     94 bool is_legal(int x,int y)
     95 {
     96     return c[x][y]!='#' && x>0 && x<=n && y>0 && y<=m;
     97 }
     98 
     99 int set_part(int state)
    100 {
    101     for(int i=0;i<cnt;i++)
    102     {
    103         if(spd[i]<=0) continue;
    104         int val=query(state,i);
    105         if(val==1) update(state,i,2);
    106     }
    107     return state;
    108 }
    109 
    110 int set_all(int state)
    111 {
    112     for(int i=0;i<cnt;i++)
    113     {
    114         int val=query(state,i);
    115         if(val==1) update(state,i,2);
    116     }
    117     return state;
    118 }
    119 
    120 int pick_up(int state,int k)
    121 {
    122     return update(state,k,1);
    123 }
    124 
    125 void init_dp()
    126 {
    127     for(int state=0;state<POW[cnt];state++)
    128     {
    129         for(int i=1;i<=n;i++)
    130         {
    131             for(int j=1;j<=m;j++)
    132             {
    133                 dp[state][i][j]=INF;
    134             }
    135         }
    136     }
    137     dp[0][start.x][start.y]=0;
    138 }
    139 
    140 sta get_front()
    141 {
    142     sta now=q.front();
    143     q.pop();
    144     vis[now.state][now.x][now.y]=false;
    145     return now;
    146 }
    147 
    148 void insert(sta now)
    149 {
    150     if(vis[now.state][now.x][now.y]) return;
    151     q.push(now);
    152     vis[now.state][now.x][now.y]=true;
    153 }
    154 
    155 void bfs(sta start)
    156 {
    157     memset(vis,false,sizeof(vis));
    158     insert(start);
    159     while(!q.empty())
    160     {
    161         sta now=get_front();
    162         int x=now.x;
    163         int y=now.y;
    164         int state=now.state;
    165         int speed=cal_spd(state);
    166         if(is_legal(x+1,y) && dp[state][x+1][y]>dp[state][x][y]+speed)
    167         {
    168             dp[state][x+1][y]=dp[state][x][y]+speed;
    169             insert(sta(state,x+1,y));
    170         }
    171         if(is_legal(x-1,y) && dp[state][x-1][y]>dp[state][x][y]+speed)
    172         {
    173             dp[state][x-1][y]=dp[state][x][y]+speed;
    174             insert(sta(state,x-1,y));
    175         }
    176         if(is_legal(x,y+1) && dp[state][x][y+1]>dp[state][x][y]+speed)
    177         {
    178             dp[state][x][y+1]=dp[state][x][y]+speed;
    179             insert(sta(state,x,y+1));
    180         }
    181         if(is_legal(x,y-1) && dp[state][x][y-1]>dp[state][x][y]+speed)
    182         {
    183             dp[state][x][y-1]=dp[state][x][y]+speed;
    184             insert(sta(state,x,y-1));
    185         }
    186         if(c[x][y]=='t')
    187         {
    188             int state_part=set_part(state);
    189             if(dp[state_part][x][y]>dp[state][x][y])
    190             {
    191                 dp[state_part][x][y]=dp[state][x][y];
    192                 insert(sta(state_part,x,y));
    193             }
    194             int state_all=set_all(state);
    195             if(dp[state_all][x][y]>dp[state][x][y])
    196             {
    197                 dp[state_all][x][y]=dp[state][x][y];
    198                 insert(sta(state_all,x,y));
    199             }
    200         }
    201         if(isupper(c[x][y]))
    202         {
    203             int state_pick=pick_up(state,c[x][y]-'A');
    204             if(dp[state_pick][x][y]>dp[state][x][y])
    205             {
    206                 dp[state_pick][x][y]=dp[state][x][y];
    207                 insert(sta(state_pick,x,y));
    208             }
    209         }
    210     }
    211 }
    212 
    213 void solve()
    214 {
    215     init_dp();
    216     bfs(sta(0,start.x,start.y));
    217 }
    218 
    219 void print()
    220 {
    221     cout<<dp[POW[cnt]-1][over.x][over.y]<<endl;
    222 }
    223 
    224 int main()
    225 {
    226     read();
    227     solve();
    228     print();
    229 }
  • 相关阅读:
    C#中ConnectionStrings和AppSettings的区别
    VS2010 生成的程序在其他电脑上不运行的问题
    装修经验
    在Linux下安装rar for linux
    判断二叉搜索树的后序遍历序列
    二维数组中的查找某个数
    Spring MVC执行原理
    将二叉搜索树转换成一个排序的双向链表
    打印二叉树中所有分支之和等于某个数
    ObjectiveC中public、protected、private的使用[转]
  • 原文地址:https://www.cnblogs.com/Leohh/p/7268458.html
Copyright © 2020-2023  润新知