HDU 3681 Prison Break(状态压缩dp + BFS)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3681
前些天花时间看到的题目,但写出不来,弱弱的放弃了。没想到现在学弟居然写出这种代码来,大吃一惊附加敬仰之情。这里借用下他的成果,好好学习吧,骚年***
题意:给出矩阵(作为监狱)和在监狱中的一个装有电池的机器人,其中
- F为出发点,图中只有一个,且初始状态下机器人在此处电池为满电量;
- D为障碍物,不可走;
- S为空格子,机器可自由通过;
- G为充电点,只能充电一次,且一次能充满电池,经过G可作为S不充电,充电后G变为S;
- Y点为电闸,机器人可通过,且通过后变为S。
机器人通过所有Y后才能飞出监狱够逃走。在此之前他只能一个格子一个格子(向上、向下、向左、向右)地走动,而且每走一格消耗一格电池的电量,如果电池没电他就不能移动。问他的电池满电量状态下至少有几格电量才能使他逃出监狱?
该题的思路来源于它的数据,Y+G的数量小于15。所以从这里就可以考虑状态压缩DP。
电量求法采用的是二分查找。
整幅图显然要进行处理,Y,F都是必须要互相连通的,若不连通,显然是无解,反之必然有解。将Y,F,G对应的编号,起点F定位0,Y,G依次编号,将Y和G分成两块编号,那么接下来对于电闸Y和充电点G的判断就会比较容易,只要直接判断编号范围即可。
接下来就是求对于每个点的最短路了,再求完最短路后,如发现Y,F间某2点无法连通,则无解,否则有解。
若有解,则进行状态压缩DP,对于每一个maxt(当前的电池满格电量),途中大于maxt的,则不能更新,反正则可以进行判断并更新。若每个Y点都已经遍历过,则判断该状态下是否可行,可行则返回TRUE。
代码如下:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int INF=<<;
int as[];
void st()
{
int i, k=;
for(i=; i<; i*=)
{
as[i]=++k;
}
}
struct Node
{
int x, y;
} nod[];
struct POS
{
POS() {}
POS(int a,int b,int c)
{
x=a,y=b,now=c;
}
int x, y, now;
} pos;
int n, m, p, q, sx, sy;
int dis[][], dp[][], the[][], num, ll;
char map[][];
bool ans;
void init() //对每个Y,F,G编号
{
int i, j;
memset(the,-,sizeof(the));
p=;
for(i=; i<n; i++)
{
for(j=; j<m; j++)
{
if(map[i][j]=='F')
sx=i, sy=j;
if(map[i][j]=='Y')
{
nod[p].x=i, nod[p].y=j;
the[i][j]=p; //该数组可用于判断某个坐标的点的编号
p++;
}
}
}
q=p;
for(i=; i<n; i++)
for(j=; j<m; j++)
{
if(map[i][j]=='G')
{
nod[q].x=i, nod[q].y=j;
the[i][j]=q;
q++;
}
}
nod[].x=sx, nod[].y=sy;
the[sx][sy]=;
for(i=; i<q; i++)
for(j=; j<q; j++)
{
if(i==j)
dis[i][j]=;
else dis[i][j]=INF;
}
}
int dx[]= {,,-,};
int dy[]= {,,,-};
bool can(int x,int y)
{
if(x<||x>=n||y<||y>=m||map[x][y]=='D')
return false;
return true;
}
void bfs() //BFS求Y,F,G之间的最短路
{
int i, j, nx, ny, x, y, now;
POS tmp;
bool vis[][];
for(i=; i<q; i++)
{
memset(vis,,sizeof(vis));
queue<POS> qq;
qq.push(POS(nod[i].x,nod[i].y,));
while(!qq.empty())
{
tmp=qq.front();
qq.pop();
x=tmp.x, y=tmp.y, now=tmp.now;
for(j=; j<; j++)
{
nx=x+dx[j], ny=y+dy[j];
if(can(nx,ny)&&!vis[nx][ny])
{
if(the[nx][ny]!=-)
dis[i][the[nx][ny]]=now+;
vis[nx][ny]=true;
qq.push(POS(nx,ny,now+));
}
}
}
}
for(i=; i<p; i++)
for(j=; j<p; j++)
if(dis[i][j]==INF) ans=false;
}
bool deal(int maxt) //状态压缩DP判断是否可行
{
int i, j, k, tmp;
for(i=; i<num; i++)
for(j=; j<q; j++)
dp[i][j]=INF;
dp[][]=;
int ed;
for(i=; i<num; i++)
{
for(j=i; j>; j-=j&(-j))
{
tmp=j&(-j);
ed=as[tmp];
for(k=; k<q; k++)
if(dp[i^tmp][k]+dis[k][ed]<=maxt)
dp[i][ed]=min(dp[i^tmp][k]+dis[k][ed],dp[i][ed]);
if(ed>=p&&dp[i][ed]!=INF)
dp[i][ed]=;
if(dp[i][ed]!=INF)
{
for(k=; k<p; k++)
{
if(dp[i][ed]+dis[ed][k]<=maxt)
dp[i|(<<(k-))][k]=min(dp[i|(<<(k-))][k],dp[i][ed]+dis[ed][k]);
}
for(; k<q; k++)
{
if((<<(k-))&i) continue;
if(dp[i][ed]+dis[ed][k]<=maxt)
dp[i|(<<(k-))][k]=;
}
}
}
if(i%ll==ll-)
{
for(j=; j<q; j++)
if(dp[i][j]<=maxt) return true;
}
}
return false;
}
int main()
{
int i, j, tmp, l, r;
st();
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==&&m==) break;
for(i=; i<n; i++)
scanf("%s",map[i]);
init();
ans=true;
bfs();
num=<<(q-); //所有状态个数
l=, r=;
ll=<<(p-);
if(ans) //ans为true表示,Y和F间两两都是连通的
{
while(l<r) //二分求解
{
m=(l+r)>>;
if(deal(m))
r=m;
else l=m+;
}
}
if(ans) printf("%d\n",r);
else puts("-1");
}
return ;
}
HDU 3681 Prison Break(状态压缩dp + BFS)的更多相关文章
- hdu 3681 Prison Break(状态压缩+bfs)
Problem Description Rompire . Now it’s time to escape, but Micheal# needs an optimal plan and he con ...
- HDU 4511 (AC自动机+状态压缩DP)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4511 题目大意:从1走到N,中间可以选择性经过某些点,比如1->N,或1->2-> ...
- HDU 3001 Travelling(状态压缩DP+三进制)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题目大意:有n个城市,m条路,每条路都有一定的花费,可以从任意城市出发,每个城市不能经过两次以上 ...
- hdu 4057(ac自动机+状态压缩dp)
题意:容易理解... 分析:题目中给的模式串的个数最多为10个,于是想到用状态压缩dp来做,它的状态范围为1-2^9,所以最大为2^10-1,那我们可以用:dp[i][j][k]表示长度为i,在tri ...
- HDU 3681 Prison Break(BFS+二分+状态压缩DP)
Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one da ...
- HDU 3681 Prison Break(状压DP + BFS)题解
题意:一张图,F是起点,Y是必须要到的点,D不能走,G可以充电.可以往四个方向走,每走一步花费一个电,走到G可以选择充满电或者不充,每个G只能充一次.问你走遍Y的最小初始点亮.number(G) + ...
- HDU 3681 Prison Break 越狱(状压DP,变形)
题意: 给一个n*m的矩阵,每个格子中有一个大写字母,一个机器人从‘F’出发,拾取所有的开关‘Y’时便能够越狱,但是每走一格需要花费1点能量,部分格子为充电站‘G’,每个电站只能充1次电.而且部分格子 ...
- hdu 3681 Prison Break (TSP问题)
Prison Break Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tot ...
- hdu 2825(ac自动机+状态压缩dp)
题意:容易理解... 分析:在做这道题之前我做了hdu 4057,都是同一种类型的题,因为题中给的模式串的个数最多只能为10个,所以我们就很容易想到用状态压缩来做,但是开始的时候我的代码超时了dp时我 ...
随机推荐
- HW3.24
public class Solution { public static void main(String[] args) { int number = (int)(Math.random() * ...
- JavaScript Garden
Objects Object Usage and Properties Everything in JavaScript acts like an object, with the only two ...
- MINA之心跳协议运用
转自:http://my.oschina.net/yjwxh/blog/174633 摘要 心跳协议,对基于CS模式的系统开发来说是一种比较常见与有效的连接检测方式,最近在用MINA框架,原本自己写了 ...
- 为什么 var_dump("1" == "1e0"); 的结果为true
今天,同学问我一个问题,如下:var_dump("1" == "1e0"); 的结果是什么. 我的第一反应,答案是false.因为很明显的要比较的是两个字符串, ...
- JavaWeb国际化
软件的国际化: 软件在不同的地方,适应不同的风格: 中国: 显示中文,以及服务符合中国习惯的文本字符串! 美国: 显示英文,以及服务符合他国习惯的文本字符串! 这种软件,就叫国际化的软件! 如何做到国 ...
- 《机器学习实战》——K近邻算法
三要素:距离度量.k值选择.分类决策 原理: (1) 输入点A,输入已知分类的数据集data (2) 求A与数据集中每个点的距离,归一化,并排序,选择距离最近的前K个点 (3) K个点进行投票,票数最 ...
- NPIV介绍
我们知道在存储区域网络(SAN:storage area network),主机(Host)能够访问后端存储(比如CLARiiON,VNX)必备的一个前提是主机必须配备HBA卡(Host Bus Ad ...
- FindWindowEx
procedure CloseGameSver(); var H1, h2: HWND; begin H1 := FindWindow('TForm1', nil); h2 := FindWindow ...
- (BUG已修改,最优化)安卓ListView异步加载网络图片与缓存软引用图片,线程池,只加载当前屏之说明
原文:http://blog.csdn.net/java_jh/article/details/20068915 迟点出更新的.这个还有BUG.因为软引应不给力了.2.3之后 前几天的原文有一个线程管 ...
- 电话qie听器
业务逻辑: 当有电话打进来或电话打出去的时候,对电话进行录音. public class TelphoneyListenerService extends Service { private stat ...