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 5
GDDSS
SSSFS
SYGYS
SGSYS
SSYSS
0 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-8
typedef __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 pf          printf
#define bug         pf("Hi\n")

using namespace std;

#define INF 0x3f3f3f3f
#define N 20

char 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;
		 }
         else
			le=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;           //我们要走所有点的最终状态是 all
                first=k;
			  	f[k++]=stud(i,j);
			  }
			  else
				if(a[i][j]=='Y')
			  {
                 all|=1<<k;
			  	 f[k++]=stud(i,j);
			  }
			  else
				if(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;
}
时间: 2024-08-08 10:21:25

HDU3681 Prison Break(状压dp)的相关文章

Hdu3681Prison Break状压Dp

#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <

HDU 3681 Prison Break(bfs+二分+状压DP)

Prison Break Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3778    Accepted Submission(s): 992 Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But on

HDU-3681-Prison Break(BFS+状压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

hdu3681(状压dp)

题意:给你一个n*m的矩阵,'F'是起点.机器人从F出发,走到G可以充电(也可以选择不充,同一个G只能充一次电),走到Y关掉开关,D不能走进,每走一步路(上下左右一格)需要消耗1点电量要求把所有开关关掉,且机器人电量上限最少,并求出该最小电量上限.   充电器数量+开关数量<=15,n,m<=15; 解法:首先我们把充电器和开关当做节点,用bfs求出每个节点之间的距离,然后二分电量,状压dp求解判别式 一开始因为忘记了两个节点之间会存在无法到达的情况,WA了几发,qaq 1 #include&

poj 2411 Mondriaan&#39;s Dream(状压DP)

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12232   Accepted: 7142 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

(状压dp)uva 10817 Headmaster&#39;s Headache

题目地址 1 #include <bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int MAX=1e5+5; 5 const int INF=1e9; 6 int s,m,n; 7 int cost[125]; 8 //char sta[MAX]; 9 string sta; 10 int able[125]; 11 int dp[125][1<<8][1<<8]; 12 in

Travel(HDU 4284状压dp)

题意:给n个城市m条路的网图,pp在城市1有一定的钱,想游览这n个城市(包括1),到达一个城市要一定的花费,可以在城市工作赚钱,但前提有工作证(得到有一定的花费),没工作证不能在该城市工作,但可以走,一个城市只能工作一次,问pp是否能游览n个城市回到城市1. 分析:这个题想到杀怪(Survival(ZOJ 2297状压dp) 那个题,也是钱如果小于0就挂了,最后求剩余的最大钱数,先求出最短路和 Hie with the Pie(POJ 3311状压dp) 送披萨那个题相似. #include <

HDU 5765 Bonds(状压DP)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5765 [题目大意] 给出一张图,求每条边在所有边割集中出现的次数. [题解] 利用状压DP,计算不同的连通块,对于每条边,求出两边的联通块的划分方案数,就是对于该点的答案. [代码] #include <cstdio> #include <algorithm> #include <cstring> using namespace std; int n,m,T,Cas=1

BZOJ1087:[SCOI2005]互不侵犯King(状压DP)

[SCOI2005]互不侵犯King Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N) Output 方案数. Sample Input 3 2 Sample Output 16 分析: 经典的状压DP题目,可我竟然调了很长时间都没对,后来发现是DP枚举范围错

poj185--炮兵阵地(状压dp)

炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 20169   Accepted: 7805 Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图.在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队):一支炮兵部队在地图上的攻击