题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3681

前些天花时间看到的题目,但写出不来,弱弱的放弃了。没想到现在学弟居然写出这种代码来,大吃一惊附加敬仰之情。这里借用下他的成果,好好学习吧,骚年***

Sample Input
5 5
GDDSS
SSSFS
SYGYS
SGSYS
SSYSS
0 0
 
Sample Output
4

题意:给出矩阵(作为监狱)和在监狱中的一个装有电池的机器人,其中

  • 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)的更多相关文章

  1. hdu 3681 Prison Break(状态压缩+bfs)

    Problem Description Rompire . Now it’s time to escape, but Micheal# needs an optimal plan and he con ...

  2. HDU 4511 (AC自动机+状态压缩DP)

    题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4511 题目大意:从1走到N,中间可以选择性经过某些点,比如1->N,或1->2-> ...

  3. HDU 3001 Travelling(状态压缩DP+三进制)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题目大意:有n个城市,m条路,每条路都有一定的花费,可以从任意城市出发,每个城市不能经过两次以上 ...

  4. hdu 4057(ac自动机+状态压缩dp)

    题意:容易理解... 分析:题目中给的模式串的个数最多为10个,于是想到用状态压缩dp来做,它的状态范围为1-2^9,所以最大为2^10-1,那我们可以用:dp[i][j][k]表示长度为i,在tri ...

  5. HDU 3681 Prison Break(BFS+二分+状态压缩DP)

    Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one da ...

  6. HDU 3681 Prison Break(状压DP + BFS)题解

    题意:一张图,F是起点,Y是必须要到的点,D不能走,G可以充电.可以往四个方向走,每走一步花费一个电,走到G可以选择充满电或者不充,每个G只能充一次.问你走遍Y的最小初始点亮.number(G) + ...

  7. HDU 3681 Prison Break 越狱(状压DP,变形)

    题意: 给一个n*m的矩阵,每个格子中有一个大写字母,一个机器人从‘F’出发,拾取所有的开关‘Y’时便能够越狱,但是每走一格需要花费1点能量,部分格子为充电站‘G’,每个电站只能充1次电.而且部分格子 ...

  8. hdu 3681 Prison Break (TSP问题)

    Prison Break Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tot ...

  9. hdu 2825(ac自动机+状态压缩dp)

    题意:容易理解... 分析:在做这道题之前我做了hdu 4057,都是同一种类型的题,因为题中给的模式串的个数最多只能为10个,所以我们就很容易想到用状态压缩来做,但是开始的时候我的代码超时了dp时我 ...

随机推荐

  1. HW2.24

    import java.util.Scanner; public class Solution { public static void main(String[] args) { Scanner i ...

  2. HDOJ-ACM2035(JAVA) 人见人爱A^B

    这道题的巧妙方法没有想出来,但是算是优化的暴力破解吧.Accepted import java.io.BufferedInputStream; import java.util.Scanner; pu ...

  3. POJ2773 - Happy 2006(欧拉函数)

    题目大意 给定两个数m,k,要求你求出第k个和m互质的数 题解 我们需要知道一个等式,gcd(a,b)=gcd(a+t*b,b) 证明如下:gcd(a+t*b,b)=gcd(b,(a+t*b)%b)= ...

  4. Codeforces Round #226 (Div. 2)A. Bear and Raspberry

    /* 贪心的找到相邻两项差的最大值,再减去c,结果若是负数答案为0. */ 1 #include <stdio.h> #define maxn 105 int num[maxn]; int ...

  5. Http协议简单解析及web请求过程

    HTTP协议: HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统. 基于HTTP协议的客户端/服务器请求响应机制的信息交换过程包含下面几个步骤: 1)    ...

  6. ajaxfileUpload ajax 上传图片使用

    前台html: <div class="b-mg15 img-text" room_id="<?= $items['id'] ?>"> ...

  7. PowerDesigner实用技巧小结(2)

    PowerDesigner实用技巧小结 1.ORACLE数据库建模时,由于ORACLE的表名.字段名如果是小写会有一定的麻烦,需要将小写转化为大写? (1)在打开pdm的情况下,进入Tools-Mod ...

  8. 在CentOS6上安装Redis

    检查安装依赖程序 yum install -y gcc-c++ tcl wget 获取安装文件 wget http://download.redis.io/releases/redis-2.8.17. ...

  9. QT下自定义QQ聊天窗口tab控件

    1.用继承pushbutton派生类来实现tab按钮,里面加一个QPushbutton关闭按钮:(自定义类:CCustomTabButton) 2.多个tab按钮用QHboxLayout做容器: 3. ...

  10. xargs i I{} 参数说明

    find . -type f | xargs -I{} md5sum {} find . -type f -name "*.txt" | xargs -i cp {} /tmp/k ...