题目链接: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. ural 1748 The Most Complex Number 和 丑数

    题目:http://acm.timus.ru/problem.aspx?space=1&num=1748 题意:求n范围内约数个数最多的那个数. Roughly speaking, for a ...

  2. arm 交叉编译时 gcc 的 Options

    https://sourceware.org/binutils/docs/as/ARM-Options.html https://gcc.gnu.org/onlinedocs/gcc-4.5.3/gc ...

  3. 局域网yum服务器创建

    yum createrepo createrepo dir 配置httpd发布yum-repo; 在客户端添加yum.rep配置文件;

  4. .NET中常见对象

    .NET中六大内置对象:1.Response    2.Request   3.Session   4.Appliction  5.Server  6.Cookie System.Web.HttpCo ...

  5. 遇到Class Not registered的COM异常怎么办

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:遇到Class Not registered的COM异常怎么办.

  6. 【转】http响应状态代码含义及跳转的类型

    转自:http://www.west263.com/info/html/caozuoxitong/FreeBSD/20090513/123479.html 当我们在因特网遨游的时候,每天都会看到诸如5 ...

  7. jQuery 编辑div内容

    div显示如下 <div id="showResult"></div> div中添加的html,进行拼接 $("#showResult" ...

  8. [Javascript] Implement zip function

    1. Use a for loop to traverse the videos and bookmarks array at the same time. For each video and bo ...

  9. C# - 系统类 - Object类

    Object类 ns:System 此类是所有.NET Framework中的类的基类 Type类就派生自Object类 C#提供了object关键字来表示一个类实例的类型 而无需使用Object作为 ...

  10. 对于POI的XSSFCell 类型问题

    1.XSSFCell.CELL_TYPE_BLANK 2.XSSFCell.CELL_TYPE_BOOLEAN 取值方式:cell.getBooleanCellValue() 3.XSSFCell.C ...