计蒜客模拟赛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 }

 

posted @ 2017-08-01 14:38  Leohh  阅读(297)  评论(0编辑  收藏  举报