HDU3681 Prison Break(状压dp)

Problem Description

Rompire is a robot kingdom and a lot of robots live there peacefully. But one day, the king of Rompire was captured by human beings. His thinking circuit was changed by human and thus became a tyrant. All those who are against him were put into jail, including our clever Micheal#1. Now it’s time to escape, but Micheal#1 needs an optimal plan and he contacts you, one of his human friends, for help.The jail area is a rectangle contains n×m little grids, each grid might be one of the following:1) Empty area, represented by a capital letter ‘S’. 2) The starting position of Micheal#1, represented by a capital letter ‘F’. 3) Energy pool, represented by a capital letter ‘G’. When entering an energy pool, Micheal#1 can use it to charge his battery ONLY ONCE. After the charging, Micheal#1’s battery will become FULL and the energy pool will become an empty area. Of course, passing an energy pool without using it is allowed.4) Laser sensor, represented by a capital letter ‘D’. Since it is extremely sensitive, Micheal#1 cannot step into a grid with a laser sensor.5) Power switch, represented by a capital letter ‘Y’. Once Micheal#1 steps into a grid with a Power switch, he will certainly turn it off.In order to escape from the jail, Micheal#1 need to turn off all the power switches to stop the electric web on the roof—then he can just fly away. Moving to an adjacent grid (directly up, down, left or right) will cost 1 unit of energy and only moving operation costs energy. Of course, Micheal#1 cannot move when his battery contains no energy.The larger the battery is, the more energy it can save. But larger battery means more weight and higher probability of being found by the weight sensor. So Micheal#1 needs to make his battery as small as possible, and still large enough to hold all energy he need. Assuming that the size of the battery equals to maximum units of energy that can be saved in the battery, and Micheal#1 is fully charged at the beginning, Please tell him the minimum size of the battery needed for his Prison break.

Input

Input contains multiple test cases, ended by 0 0. For each test case, the first line contains two integer numbers n and m showing the size of the jail. Next n lines consist of m capital letters each, which stands for the description of the jail.You can assume that 1<=n,m<=15, and the sum of energy pools and power switches is less than 15.

Output

For each test case, output one integer in a line, representing the minimum size of the battery Micheal#1 needs. If Micheal#1 can’t escape, output -1.

Sample Input

5 5GDDSSSSSFSSYGYSSGSYSSSYSS0 0

Sample Output

4

题目:机器人从F出发,走到G可以充电,走到Y关掉开关,D不能走进,要求把所有开关关掉,,且电量最少,并求出该最小电量。

思路:因为我们必须要到的是 Y F, 可能到的是 G,我们把必须到的状态设置为 下面代码的all,所有的状态为len,然后根据当前状态可以更新哪些状态进行dp,这个题不清楚的地方是 G,题目说到了这个点可以充电,也可以不充电,可能下次来在充电,不过最好不要多想,到了G就充电吧

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<queue>#include<stack>#include<vector>#include<set>#include<map>#define L(x) (x<<1)#define R(x) (x<<1|1)#define MID(x,y) ((x+y)>>1)#define eps 1e-8typedef __int64 ll;#define fre(i,a,b) for(i = a; i <b; i++)#define mem(t, v) memset ((t) , v, sizeof(t))#define ssf(a)scanf("%s",a)#define sf(n)scanf("%d", &n)#define sff(a,b) scanf("%d %d", &a, &b)#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)#define pfprintf#define bugpf("Hi\n")using namespace std;#define INF 0x3f3f3f3f#define N 20char a[N][N];int dis[N][N][N][N];int k;int n,m;int first,all;int dp[1<<16][16]; //dp[s][i] s状态下最后到达 i 点 还有的油int step[4][2]={1,0,-1,0,0,1,0,-1};int vis[N][N];struct stud{ stud(){}; stud(int _x,int _y):x(_x),y(_y),time(0){} stud(int _x,int _y,int _time):x(_x),y(_y),time(_time){} int x,y; int time;}f[N*N];inline bool judge(int x,int y){if(x>=0&&x<n&&y>=0&&y<m) return true;return false;}void bfs(int t){queue<stud>q;int i,j;f[t].time=0;q.push(f[t]);stud cur;cur=f[t];dis[cur.x][cur.y][cur.x][cur.y]=0;mem(vis,0);vis[cur.x][cur.y]=1;while(!q.empty()){cur=q.front();q.pop();fre(i,0,4){int xx=cur.x+step[i][0];int yy=cur.y+step[i][1];if(judge(xx,yy)&&a[xx][yy]!='D'&&!vis[xx][yy]){dis[f[t].x][f[t].y][xx][yy]=cur.time+1; //起始点和这个点的距离vis[xx][yy]=1;q.push(stud(xx,yy,cur.time+1));}}}}bool check(int now){int i,j;mem(dp,-1);dp[1<<first][first]=now;int cur,len=1<<k;int to,ans=-1;fre(cur,0,len) fre(i,0,k) {if((cur&(all))==all) ans=max(ans,dp[cur][i]); //走过该走的点了if(ans!=-1) return true;if(!(cur&(1<<i))) continue; // cur 应该是走过 i 的if(dp[cur][i]==-1) continue; //这种状态没有走到过fre(to,0,k)//枚举下一个点{if(cur&(1<<to)) continue;if(dis[f[i].x][f[i].y][f[to].x][f[to].y]==-1) continue; //两者无法到达if(i==to) continue;int time=dp[cur][i]-dis[f[i].x][f[i].y][f[to].x][f[to].y]; //从 i 走到 to 后剩下的油if(time<0) continue;int next=cur+(1<<to);dp[next][to]=max(dp[next][to],time);if(a[f[to].x][f[to].y]=='G') dp[next][to]=now; //如果现在到达的点 可以加油//(其实我感觉这里是有bug的,可能别人先到这个点不加油,下一次到的时候加油)} } return false;}int solve()//二分答案{int le,ri,mid;int ans=300;le=0;ri=300;int i=0;while(le<=ri){ mid=(le+ri)>>1;if(check(mid)) //判断mid可否满足条件 {ans=mid;ri=mid-1; }elsele=mid+1;}if(ans==300)return -1;return ans;}int main(){int i,j;//freopen("in.txt","r",stdin);while(~sff(n,m),n+m){fre(i,0,n)ssf(a[i]);all=0;k=0;fre(i,0,n) fre(j,0,m) {if(a[i][j]=='F'){all|=1<<k;//我们要走所有点的最终状态是 allfirst=k;f[k++]=stud(i,j);}elseif(a[i][j]=='Y'){all|=1<<k;f[k++]=stud(i,j);}elseif(a[i][j]=='G')f[k++]=stud(i,j); }int t,tt;fre(i,0,20)fre(j,0,20)fre(t,0,20)fre(tt,0,20)dis[i][j][t][tt]=-1;fre(i,0,k)bfs(i); //求出任意两个点的距离int ans=solve();pf("%d\n",ans);}return 0;}

吃水不忘挖井人。

HDU3681 Prison Break(状压dp)

相关文章:

你感兴趣的文章:

标签云: