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时我 ...
随机推荐
- spring 的配置 bean>>property>>name属性
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...
- if
语句快中的变量与函数的局部变量关系;
- Ⅸ.spring的点点滴滴--IObjectFactory与IFactoryObject的杂谈
承接上文 ObjectFactory与IFactoryObject的杂谈 .net篇(环境为vs2012+Spring.Core.dll v1.31) public class parent { pu ...
- 一段经典的node.js 数据库高并发实现
var proxy = new EventProxy();var status = "ready";var select = function(callback){ proxy.o ...
- 【转】Spring的WebServiceTemplate访问WebService的方法及其本质原理
WebService客户端调用的本质就是将SAOP格式的XML通过通信协议发送到WebService的服务器端,然后接收服务器端返回的XML. 本文简单介绍一下如何通过Spring提供的WebServ ...
- FireMonkey 使用Webbrowser
DELPHI XE5 源码PASCAL:http://files.cnblogs.com/xe2011/FireMonkey_Webbrowser.rar 为了这个用上webbrowser真是费太大劲 ...
- Xutils 源码解析【转】
原文:http://my.oschina.net/u/1538627/blog/395098 目录[-] 1. 功能介绍 2. 详细设计 2.1 View模块 2.1.1 总体设计 2.1.2 流程图 ...
- JAVA Web 之 struts2文件上传下载演示(一)(转)
JAVA Web 之 struts2文件上传下载演示(一) 一.文件上传演示 1.需要的jar包 大多数的jar包都是struts里面的,大家把jar包直接复制到WebContent/WEB-INF/ ...
- 深入理解JavaScript系列+ 深入理解javascript之执行上下文
http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html http://blog.csdn.net/hi_kevin/article/d ...
- iphone4s 关于大于400M的视频无法拷贝的问题
方法有二: 1.可以用win7等高版本的系统拷出 2.可以用Itools工具导出