题目大意:

输入w h,接下来输入h行w列的图

':干净的点;  ' * ' :垃圾;  ' ' : 墙;  ' ' : 初始位置;

输出 清理掉所有垃圾的最短路径长度 无则输出-1

Sample Input

7 5
.......
.o...*.
.......
.*...*.
.......
15 13
.......x.......
...o...x....*..
.......x.......
.......x.......
.......x.......
...............
xxxxx.....xxxxx
...............
.......x.......
.......x.......
.......x.......
..*....x....*..
.......x.......
10 10
..........
..o.......
..........
..........
..........
.....xxxxx
.....x....
.....x.*..
.....x....
.....x....
0 0

Sample Output

8
49
-1

题解

用bfs求出任意两点间的距离然后转换成tsp问题,用dfs解

/*
题意:给一个 n*m的图,有一个机器人从一点开始清理垃圾,要求把所有的垃圾清理完,求最短的路径 思路:这个题可以先用bfs求出任意两点间的距离然后转换成tsp问题,用dfs解。 这个题还可以用状态压缩bfs写,但写了一次没过,再试试。
*/ #include <cstdlib>
#include <stdio.h>
#include <string.h>
#include <queue> #define INF 0x7fffffff
#define N 22 using namespace std; struct node
{
int x,y,step;
}p[N*N],s,e; char map[N][N];
int n,m,d[][]={,,,,,-,-,},used[N][N];
int dis[N][N],ans,use[N],cnt; bool ok(int x,int y)
{
return x>=&&x<n&&y>=&&y<m&&map[x][y]!='x'&&!used[x][y];
} int bfs()
{
memset(used,,sizeof(used));
int i;
queue<node> q;
q.push(s);
while(!q.empty())
{
node cur=q.front(),next;
q.pop();
for(i=;i<;i++)
{
next.x=cur.x+d[i][];
next.y=cur.y+d[i][];
next.step=cur.step+;
if(ok(next.x,next.y))
{
used[next.x][next.y]=;
if(next.x==e.x&&next.y==e.y)
return next.step;
q.push(next);
}
}
}
return INF;
} void dfs(int s,int num,int length)
{
int j;
if(num==&&ans>length)
{
ans=length;
return ;
}
if(length>ans)
return ;
for(j=;j<cnt;j++)
{
if(dis[s][j]!=INF&&!use[j])
{
use[j]=;
length+=dis[s][j];
dfs(j,num-,length);
num+;
length-=dis[s][j];
use[j]=;
}
}
} int main()
{
int i, j, start, flag;
while(scanf("%d%d",&m,&n)&&(n||m))
{
cnt=flag=;
for(i=;i<n;i++)
{
scanf("%s",map[i]);
for(j=;j<m;j++)
{
if(map[i][j]=='o'||map[i][j]=='*')
{
p[cnt].x=i,p[cnt].y=j;
if(map[i][j]=='o')
start=cnt;
cnt++; }
dis[i][j]=INF;
}
} //memset(dis,INF,sizeof(dis));
for(i=;i<cnt;i++)
for(j=i+;j<cnt;j++)
{
s=p[i],e=p[j],s.step=;
dis[i][j]=dis[j][i]=bfs();
if(dis[i][j]==INF)
{
flag=;
break;
}
}
/* for(i=0;i<cnt;i++)
{
for(j=0;j<cnt;j++)
printf("%d\t",dis[i][j]);
puts("");
}*/
if(flag)
puts("-1");
else
{
ans=INF;
memset(use,,sizeof(use));
use[start]=;
dfs(start,cnt-,);
printf("%d\n",ans);
}
}
return ;
}

状压 BFS

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
struct NODE
{
int ni,nj,mask,len;
NODE(){};
NODE(int n_i,int n_j,int nmask,int nlen):
ni(n_i),nj(n_j),mask(nmask),len(nlen){};
};
char G[][];
int w,h,cnt,st_i,st_j;
int vis[][][<<],flag[][];
int mi[]={,,,-},mj[]={,-,,}; bool bound(int i,int j) /// 判断是否越界
{
return (i>h||i<||j>w||j<);
}
bool OK(int mask) /// 判断垃圾是否被清理
{
for(int i=;i<cnt;i++)
if(mask & (<<i)); /// 用mask二进制的各个位表示各个垃圾
else return ;
return ;
}
int BFS()
{
memset(vis,,sizeof(vis));
int ans=INF;
queue<NODE> q;
q.push(NODE(st_i,st_j,,)); /// 构造函数的便利之处 while(!q.empty())
{
NODE tmp=q.front(); q.pop(); if(OK(tmp.mask)) /// 返回1表明垃圾清理光了 就更新ans值
{
ans=min(ans,tmp.len);
continue;
} if(vis[tmp.ni][tmp.nj][tmp.mask]) continue;
/// 该点的mask状态已出现过 则忽略该点
else vis[tmp.ni][tmp.nj][tmp.mask]=;
/// 未出现过 则标记为已出现过 for(int i=;i<;i++)
{
int newi=tmp.ni+mi[i],newj=tmp.nj+mj[i],newmask=tmp.mask; if(bound(newi,newj)||G[newi][newj]=='x') continue;
/// 若越界或该点为墙 则忽略该点 if(G[newi][newj]=='*')
newmask=tmp.mask | (<<flag[newi][newj]);
/* 假如目前是三号垃圾 更新状态
即若此时tmp.mask的二进制为011(第一二号垃圾已清除)
newmask=011 | 1<<3=111(第一二三号垃圾已清除)
很明显 将垃圾状态压缩 用mask的二进制表示 */ if(vis[newi][newj][newmask]) continue;
/// 若该新点的该状态已出现过 则忽略该点 若无则放入队列
q.push(NODE(newi,newj,newmask,tmp.len+));
}
}
return ans==INF ? -:ans;
} int main()
{
while(~scanf("%d%d",&w,&h)&&(w||h))
{
cnt=;
for(int i=;i<=h;i++)
for(int j=;j<=w;j++)
{
scanf(" %c",&G[i][j]);
if(G[i][j]=='o') st_i=i,st_j=j; /// 记下所在位置
else if(G[i][j]=='*') flag[i][j]=cnt++;
/// 记下垃圾的位置 并为其编号 防止重复清扫
}
if(!cnt) printf("0\n");
else printf("%d\n",BFS());
} return ;
}

Japan 2005 Domestic Cleaning Robot /// BFS 状压 二进制位运算 结构体内构造函数 oj22912的更多相关文章

  1. 孤岛营救问题 (BFS+状压)

    https://loj.ac/problem/6121 BFS + 状压 写过就好想,注意细节debug #include <bits/stdc++.h> #define read rea ...

  2. hdu 5094 Maze (BFS+状压)

    题意: n*m的迷宫.多多要从(1,1)到达(n,m).每移动一步消耗1秒.有P种钥匙. 有K个门或墙.给出K个信息:x1,y1,x2,y2,gi    含义是(x1,y1)与(x2,y2)之间有gi ...

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

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

  4. HDU-3681-Prison Break(BFS+状压DP+二分)

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

  5. 【BZOJ 3049】【USACO2013 Jan】Island Travels BFS+状压DP

    这是今天下午的互测题,只得了60多分 分析一下错因: $dis[i][j]$只记录了相邻的两个岛屿之间的距离,我一开始以为可以,后来$charge$提醒我有可能会出现来回走的情况,而状压转移就一次,无 ...

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

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

  7. hdu 4856 Tunnels (bfs + 状压dp)

    题目链接 The input contains mutiple testcases. Please process till EOF.For each testcase, the first line ...

  8. 【HDU 4771 Stealing Harry Potter's Precious】BFS+状压

    2013杭州区域赛现场赛二水... 类似“胜利大逃亡”的搜索问题,有若干个宝藏分布在不同位置,问从起点遍历过所有k个宝藏的最短时间. 思路就是,从起点出发,搜索到最近的一个宝藏,然后以这个位置为起点, ...

  9. hdu 2209 bfs+状压

    http://acm.hdu.edu.cn/showproblem.php?pid=2209 不知为啥有种直觉.会出状压+搜索的题,刷几道先 简单的BFS.状压表示牌的状态, //#pragma co ...

随机推荐

  1. 卿烨科技 Fireball

    9人开发病毒感染超2亿电脑!Fireball病毒境外做案被举报   原标题:名校毕业生研发病毒年获利8000万 2.5亿台电脑感染 海淀网友协助民警追踪跨境黑客 高材生开公司研发病毒 一年获利8000 ...

  2. ()获取Cookies session

    [HttpGet] public string mo() { var httpRequest = HttpContext.Current.Request; var a = httpRequest.Co ...

  3. angularJS 上传multipart/form-data

    var fd = new FormData();fd.append('file', vm.file);CommodityViewImport.post(fd, onSaveSuccess, onSav ...

  4. selenium 滑动页面至元素可见

    滚动页面 在自动化操作中,如果web页面过长,而我们需要的元素并不在当前可视页面中,那么selenium就无法对其进行操作:此时,我们就需要像平时操作浏览器一样来滚动页面,使我们需要操作的对象可见! ...

  5. zabbix--添加用户

    用户和用户组   概述 Zabbix 中的所有用户都通过 Web 前端去访问 Zabbix 应用程序.并为每个用户分配唯一的登陆名和密码. 所有用户的密码都被加密并储存于 Zabbix 数据库中.用户 ...

  6. win10命令行kill进程

    1. 查:netstat -ano | findstr "8080" 2. 杀:taskkill -PID 8082 -F

  7. ForEach控制器

    ForEach一般是和用户定义的变量结合使用的 前面前缀一般是和用户定义的变量前缀一致 输出的变量是要使用的变量 这样能保证每次使用的变量不一样 add"_"before numb ...

  8. 标准 IO 测试 标准输出,输入,出错缓冲大小;全缓冲文本流大小

    例子:测试缓冲区大小 #include <stdio.h> int main(int argc, const char *argv[]) { //标准输入大小,没有输入内容时,标准输入缓冲 ...

  9. linux redis的启动---后台启动

    1.启动redis服务: redis-server 如果想要开启后台进程: 1.找到redis.conf里边的 把no 改为yes. 2.redis-server redis.conf(这个是针对两个 ...

  10. JavaScript ---- 闭包(什么是闭包,为什么使用闭包,闭包的作用)

    经常被问到什么是闭包? 说实话闭包这个概念很难解释.JavaScript权威指南里有这么一段话:“JavaScript函数是将要执行的代码以及执行这些代码作用域构成的一个综合体.在计算机学术语里,这种 ...