2013杭州区域赛现场赛二水。。。

类似“胜利大逃亡”的搜索问题,有若干个宝藏分布在不同位置,问从起点遍历过所有k个宝藏的最短时间。

思路就是,从起点出发,搜索到最近的一个宝藏,然后以这个位置为起点,搜索下一个最近的宝藏,直至找到全部k个宝藏。有点贪心的感觉。

由于求最短时间,BFS更快捷,但耗内存,这道题就卡在这里了。。。

这里记录了我几次剪枝的历史。。。题目要求内存上限32768KB,就差最后600KB了。。。但我从理论上觉得已经不能再剪了,留下的结点都是盲目式搜索必然要访问的结点。

在此贴上剪枝到33292KB的代码,注释里说明了剪掉的部分(剪枝策略可能还有不正确的地方,仅供参考)

 #include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int MAX_N=;
int n,m,k;
int sx,sy;
int dx[]={,,,-},dy[]={,-,,};
char G[MAX_N+][MAX_N+];
int cur_step; struct Node
{
int x,y,step,g;//每个点的坐标、走到这里的步数、到这一点已找到的宝藏数
Node(){}
Node(int xx,int yy,int ss,int gg):x(xx),y(yy),step(ss),g(gg){}
}; int bfs()
{
int get=;//全局已找到的宝藏数,小于这个数的结点视为“过期”
queue<Node> que;
que.push(Node(sx,sy,,));
cur_step=-;//全局当前的步数
while(!que.empty())
{
Node cur=que.front();
que.pop();
//当此点步数小于等于到达某一个宝藏的步数(即和这个宝藏在搜索树中“同层”),剪枝
if(cur.step<=cur_step&&cur.g<get) continue;
int has=;//这一点的四个可扩展结点中有没有是宝藏的
for(int i=;i<;i++)
{
int nx=cur.x+dx[i];
int ny=cur.y+dy[i];
if(nx<||ny<||nx>n||ny>m) continue;
if(G[nx][ny]=='#') continue;
if(cur.g<get) continue;//宝藏数过期
if(G[nx][ny]=='*')//是宝藏
{
has++;
sx=nx;
sy=ny;
}
}
if(has)
{//一旦四个结点有一个是宝藏,则只将这一个入队,由于没有设vis数组!!!同层其他宝藏会在之后被推入队列的
cur.g++;
get=cur.g;
G[sx][sy]='.';
cur_step=cur.step+;
if(get==k) return cur.step+;
que.push(Node(sx,sy,cur.step+,cur.g));
continue;
}
//当四个结点都不是宝藏时,根据盲目式搜索策略,只好全部推入队列,就在这里推入了很多无用但又无法提前预知的点
for(int i=;i<;i++)
{
int nx=cur.x+dx[i];
int ny=cur.y+dy[i];
if(nx<||ny<||nx>n||ny>m) continue;
if(G[nx][ny]=='#') continue;
if(cur.g<get) continue;
que.push(Node(nx,ny,cur.step+,cur.g));
}
}
if(get<k) return -;
} int main()
{
//freopen("1002.txt","r",stdin);
while((scanf("%d%d",&n,&m)!=EOF)&&(!(n==&&m==)))
{
for(int i=;i<=n;i++)
{
getchar();
for(int j=;j<=m;j++)
{
scanf("%c",&G[i][j]);
if(G[i][j]=='@')
{
sx=i;
sy=j;
}
}
}
scanf("%d",&k);
for(int i=;i<k;i++)
{
int x,y;
scanf("%d%d",&x,&y);
G[x][y]='*';//宝藏标记为*
}
printf("%d\n",bfs());
}
return ;
}

BFS 剪枝 无状压

就在无计可施时,队友建议我改用DFS,但目测会超时或爆栈;而且总觉得原思路是对的,问题在优化上。

这时重新看题,发现我居然忽略了一个条件k<=4~~~~~~~~~~有经验的人大概早就会想到状压了,然而我经验还太少,并是没想到,想到了也写不出来。。。

之后找题解,发现很多是用BFS求出起点和宝藏的最短路,然后再DFS或枚举所有路径。并是没有想通这个思路。

再找,终于发现有和我相同思路的了,感谢原作者~ http://blog.csdn.net/u011932355/article/details/40819317 于是参照这篇把自己的改成了状压版,然后,就得到了内存和时间都少了一个数量级的结果。。。状压大法好~

 #include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int MAX_N=;
int n,m,k;
int sx,sy,goal;
int dx[]={,,,-},dy[]={,-,,};
int b[]={,,,,};//原作者的写法,这个数组有大用~
char G[MAX_N+][MAX_N+];
int vis[MAX_N+][MAX_N+][];//第三维是状压,表示当前已得宝藏状态 1111~0000
char str[]; struct Node
{
int x,y,step,get;//走到这一点的步数,到这一点的已得宝藏状态
Node(){}
Node(int xx,int yy,int ss,int gg):x(xx),y(yy),step(ss),get(gg){}
}; int bfs()
{
memset(vis,,sizeof(vis));
queue<Node> que;
que.push(Node(sx,sy,,));
vis[sx][sy][]=;
while(!que.empty())
{
Node cur=que.front();
que.pop();
for(int i=;i<;i++)
{
int nx=cur.x+dx[i];
int ny=cur.y+dy[i];
if(nx<||ny<||nx>n||ny>m) continue;
if(G[nx][ny]=='#') continue; Node next(nx,ny,cur.step+,cur.get);
if(G[nx][ny]<=) next.get|=G[nx][ny];//找到一处宝藏,追加到当前宝藏状态
if(vis[nx][ny][next.get]) continue;//同一点同一宝藏状态,只入队一次
vis[nx][ny][next.get]=;
if(next.get==goal) return next.step;//找到全部宝藏,返回
que.push(next);
}
}
return -;
} int main()
{
//freopen("1002.txt","r",stdin);
while(scanf("%d%d",&n,&m)==)
{
if(n==&&m==) break;
for(int i=;i<=n;i++)
{
scanf("%s",str);
int cnt=;
for(int j=;str[j]!='\0';j++)
{
if(str[j]=='#') G[i][cnt++]='#';
else if(str[j]=='.') G[i][cnt++]='.';
else if(str[j]=='@')
{
G[i][cnt++]='@';
sx=i;
sy=cnt-;
}
}
}
scanf("%d",&k);
goal=b[k]-;//通过k和b数组得到目标状态(1111,111,11,1,0之一)
while(k--)
{//按先后顺序,把每个宝藏所在点的状态设为(1,10,100,1000之一)
int x,y;
scanf("%d%d",&x,&y);
G[x][y]=b[k];
}
printf("%d\n",bfs());
}
return ;
}

这个状压是把当前的宝藏访问状态作为vis数组的第三维存入,这样用vis数组对于我来说是第一次,而我的无状压版本大概就是因为没设vis数组,所以本身就增加了很多无用节点的推入,取出后再丢弃就不叫剪枝了。。。因为还是被推入队列了。。。

比赛时一直纠结一道题是我的不对,感谢两位队友的指教。

场下这样的过程还是比较利于学习的,关键是在纠结的过程中暴露了自己哪些基础知识还不清楚,给自己提供了补习的方向。

【HDU 4771 Stealing Harry Potter's Precious】BFS+状压的更多相关文章

  1. hdu 4771 Stealing Harry Potter's Precious (BFS+状压)

    题意: n*m的迷宫,有一些格能走("."),有一些格不能走("#").起始点为"@". 有K个物体.(K<=4),每个物体都是放在& ...

  2. HDU 4771 Stealing Harry Potter's Precious (2013杭州赛区1002题,bfs,状态压缩)

    Stealing Harry Potter's Precious Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 ...

  3. HDU 4771 Stealing Harry Potter's Precious dfs+bfs

    Stealing Harry Potter's Precious Problem Description Harry Potter has some precious. For example, hi ...

  4. HDU 4771 Stealing Harry Potter's Precious

    Stealing Harry Potter's Precious Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 ...

  5. HDU Stealing Harry Potter's Precious(状压BFS)

    状压BFS 注意在用二维字符数组时,要把空格.换行处理好. #include<stdio.h> #include<algorithm> #include<string.h ...

  6. hdu 4771 Stealing Harry Potter's Precious (2013亚洲区杭州现场赛)(搜索 bfs + dfs) 带权值的路径

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4771 题目意思:'@'  表示的是起点,'#' 表示的是障碍物不能通过,'.'  表示的是路能通过的: ...

  7. hdu 4771 Stealing Harry Potter&#39;s Precious(bfs)

    题目链接:hdu 4771 Stealing Harry Potter's Precious 题目大意:在一个N*M的银行里,贼的位置在'@',如今给出n个宝物的位置.如今贼要将全部的宝物拿到手.问最 ...

  8. Stealing Harry Potter's Precious BFS+DFS

    Problem Description Harry Potter has some precious. For example, his invisible robe, his wand and hi ...

  9. HDU 5025:Saving Tang Monk(BFS + 状压)

    http://acm.hdu.edu.cn/showproblem.php?pid=5025 Saving Tang Monk Problem Description   <Journey to ...

随机推荐

  1. linux系统下,11款常见远程桌面控制软件

    linux系统下,11款常见远程桌面控制软件 一. Grdc 它是一个用GTK+编写的,适用于gnome桌面环境的远程桌面访问软件.看图: 常见功能: 1.提供全屏,窗口化的远程控制.支持高分辨率下的 ...

  2. [Leetcode][Python]56: Merge Intervals

    # -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 56: Merge Intervalshttps://oj.leetcode. ...

  3. ObjectOutputStream 追加写入读取错误 - 自己的实现方案

    本篇博客灵感来自http://blog.csdn.net/chenssy/article/details/13170015 问题描述.问题出现的原因.尝试解决办法,请参见鄙人上一编博客. 上一编文章解 ...

  4. magento后台登陆后,没任何提示,又跳转到登陆页面

    这个问题通常是cookie配置的问题.需要去将core_config_data中web/cookie/cookie_path.web/cookie/cookie_domain设为null

  5. 格而知之8:我所理解的Runtime(3)

    关联对象 14.使用Category对类进行拓展的时候,只能添加方法,而不适合添加属性(可以添加属性,也可以正常使用get方法和set方法,只是不会自动生成以下划线开头命名的成员变量). 可以通过关联 ...

  6. 格而知之6:我所理解的Runtime(1)

    基本简介 1.根据官方文档,OC有一个特性:它会尽可能把一些决定从编译时和链接时推迟到运行时才处理,所以这门语言需要的就不只是一个编译器,它还需要一个runtime系统来处理那些已经被编译过的代码. ...

  7. ModelAndView解析

    查看spring的帮助文档得到下面信息: org.springframework.web.servlet Class ModelAndViewjava.lang.Object org.springfr ...

  8. @page指令 validateRequest的作用

    在 Web 应用程序中,要阻止依赖于恶意输入字符串的黑客攻击,约束和验证用户输入是必不可少的.跨站点脚本攻击就是此类攻击的一个示例.其他类型的恶意数据或不需 要的数据可以通过各种形式的输入在请求中传入 ...

  9. WPS页面设置

    以前使用WPS的时候遇到一些问题: 比如我输入一个英文的时候它总是自动的给我首字母大写,但是某些情况下我不想这样: 从VS中复制代码的时候不希望他吧那些颜色复制下来: 还有我输入1回车后它自动给我输入 ...

  10. java学习之数据库

    第一部分:DB2基础知识 一.复习 jre jdk jvm path classpath 二.数据库基础-DB2 1.访问172.22.602.24/ temp 123 2.安装检查 db2cmd d ...