Japan 2005 Domestic Cleaning Robot /// BFS 状压 二进制位运算 结构体内构造函数 oj22912

Japan 2005 Domestic Cleaning Robot /// BFS 状压 二进制位运算 结构体内构造函数 oj22912

题目大意:

输入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[4][2]={0,1,1,0,0,-1,-1,0},used[N][N];
int dis[N][N],ans,use[N],cnt;

bool ok(int x,int y)
{
    return x>=0&&x<n&&y>=0&&y<m&&map[x][y]!='x'&&!used[x][y];
}

int bfs()
{
    memset(used,0,sizeof(used));
    int i;
    queue<node> q;
    q.push(s);
    while(!q.empty())
    {
        node cur=q.front(),next;
        q.pop();
        for(i=0;i<4;i++)
        {
            next.x=cur.x+d[i][0];
            next.y=cur.y+d[i][1];
            next.step=cur.step+1;
            if(ok(next.x,next.y))
            {
                used[next.x][next.y]=1;
                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==0&&ans>length)
    {
        ans=length;
        return ;
    }
    if(length>ans)
        return ;
    for(j=0;j<cnt;j++)
    {
        if(dis[s][j]!=INF&&!use[j])
        {
            use[j]=1;
            length+=dis[s][j];
            dfs(j,num-1,length);
            num+1;
            length-=dis[s][j];
            use[j]=0;
        }
    }
}

int main()
{
    int i, j, start, flag;
    while(scanf("%d%d",&m,&n)&&(n||m))
    {
        cnt=flag=0;
        for(i=0;i<n;i++)
        {
            scanf("%s",map[i]);
            for(j=0;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=0;i<cnt;i++)
            for(j=i+1;j<cnt;j++)
            {
                s=p[i],e=p[j],s.step=0;
                dis[i][j]=dis[j][i]=bfs();
                if(dis[i][j]==INF)
                {
                    flag=1;
                    break;
                }
            }
/*       for(i=0;i<cnt;i++)
        {
            for(j=0;j<cnt;j++)
                printf("%d	",dis[i][j]);
            puts("");
        }*/ 
        if(flag)
            puts("-1");
        else
        {
            ans=INF;
            memset(use,0,sizeof(use));
            use[start]=1;
            dfs(start,cnt-1,0);
            printf("%d
",ans);
        }
    }
    return 0;
}
View Code

状压 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[35][35];
int w,h,cnt,st_i,st_j;
int vis[35][35][1<<11],flag[35][35];
int mi[]={0,0,1,-1},mj[]={1,-1,0,0};

bool bound(int i,int j) /// 判断是否越界
{
    return (i>h||i<1||j>w||j<1);
}
bool OK(int mask) /// 判断垃圾是否被清理
{
    for(int i=0;i<cnt;i++)
        if(mask & (1<<i)); /// 用mask二进制的各个位表示各个垃圾
        else return 0;
    return 1;
}
int BFS()
{
    memset(vis,0,sizeof(vis));
    int ans=INF;
    queue<NODE> q;
    q.push(NODE(st_i,st_j,0,0)); /// 构造函数的便利之处

    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]=1;
        /// 未出现过 则标记为已出现过 

        for(int i=0;i<4;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 | (1<<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+1));
        }
    }
    return ans==INF ? -1:ans; 
}

int main()
{
    while(~scanf("%d%d",&w,&h)&&(w||h))
    {
        cnt=0;
        for(int i=1;i<=h;i++)
            for(int j=1;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
");
        else printf("%d
",BFS());
    }

    return 0;
}
View Code