The Morning after Halloween Uva-1061(搜索)

链接:https://vjudge.net/problem/UVA-1601

题目大意

有一个大小h*w的迷宫鬼屋,鬼屋中有障碍和鬼,万圣节过后鬼屋有n(n<=3)个鬼不在原来的位置了,要求通过操作将他们放回原来的位置,每次操作满足以下条件:

  1. 每只鬼可以在一次操作中选择移动一步或不动
  2. 不能有两只以上的鬼在同一格中,也不能两只鬼之间进行位置的互换
  3. 障碍不可行走
  4. 每一个2*2的格子都至少会有一个障碍

'#'代表障碍,a,b,c分别代表三只鬼的初始位置;A,B,C代表要到达的位置.
求最少需要操作的次数.
数据范围:
4<=w<=16 4<=h<=16

思路

将三只鬼的位置压缩成状态,由初始状态向目标状态进行搜索.直接暴力搜索的话貌似会超时,注意到题目给出的"每一个2 * 2的格子都至少会有一个障碍",也就是有很多位置都不能走到.所以我们可以抽出每一个格子可以到达的下一个格子建立一张新的图,可以大大降低时间复杂度.建立判重数组的大小为16* 16* 16* 16* 16* 16=16777216.空间略大在poj上会MLE,可改用bool型并采用结构体存储状态,而Uva没限制空间,所以我为了方便直接开大数组了…

三种方法:普通bfs,双向bfs,A*.

普通bfs(1150ms)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
#include<cmath>
#include<string>
#include<vector>
#include<map>
#include<stack>
#include<queue>
#define INF 0x3f3f3f3f
#define mod 1000000007
#define MAXN 16
#define end END
typedef long long ll;
using namespace std;
int r,c,n;
string maze[MAXN];
int vis[MAXN*MAXN][MAXN*MAXN][MAXN*MAXN];///标记判重数组
int dx[]={
    
    1,-1,0,0,0};
int dy[]={
    
    0,0,1,-1,0};
int start[3],end[3];
vector<int> g[MAXN*MAXN];
int getid(int a,int b,int c)
{
    
    
    return (a<<16)|(b<<8)|c; ///对状态进行编码
}
bool no(int a,int b,int na,int nb)
{
    
    
    return (na==nb)||(a==nb&&b==na);///判断a和b是否走到同一个位置或位置交换了
}
int bfs()
{
    
    
    queue<int> q;
    q.push(getid(start[0],start[1],start[2]));
    while(!q.empty())
    {
    
    
        int cur=q.front();q.pop();
        int a=(cur>>16)&0xff,b=(cur>>8)&0xff,c=cur&0xff;///解码
        for(int i=0;i<g[a].size();++i)
        {
    
    
            int na=g[a][i];
            for(int j=0;j<g[b].size();++j)
            {
    
    
                int nb=g[b][j];
                if(!no(a,b,na,nb))
                for(int k=0;k<g[c].size();++k)
                {
    
    
                    int nc=g[c][k];
                    if(no(a,c,na,nc)||no(b,c,nb,nc))continue;
                    if(vis[na][nb][nc]!=-1)continue;
                    q.push(getid(na,nb,nc));
                    vis[na][nb][nc]=vis[a][b][c]+1;
                    if(na==end[0]&&nb==end[1]&&nc==end[2])return vis[na][nb][nc];
                }
            }
        }
    }

}
int main()
{
    
    
    //ios::sync_with_stdio(false);
    while(cin>>c>>r>>n&&(r||c||n))
    {
    
    
        memset(vis,-1,sizeof(vis));
        char ch=getchar();
        for(int i=0;i<r;++i)
            getline(cin,maze[i]);
        for(int i=0;i<MAXN*MAXN;++i)g[i].clear();
        for(int i=0;i<r;++i)
        {
    
    
            for(int j=0;j<c;++j)
            {
    
    
                int cur=i*c+j;
                if(isupper(maze[i][j]))end[maze[i][j]-'A']=cur;///初始
                if(islower(maze[i][j]))start[maze[i][j]-'a']=cur;///目标
                if(maze[i][j]!='#')
                for(int k=0;k<5;k++)
                {
    
    
                    int nx=i+dx[k],ny=j+dy[k];
                    if(maze[nx][ny]!='#')
                    {
    
    
                        int next=nx*c+ny;
                        g[cur].push_back(next);///存放这个点的下一个可达的点
                    }
                }
            }
        }
        if(n<3)
        {
    
    
            start[2]=end[2]=0;g[0].push_back(0);
            if(n<2){
    
    start[1]=end[1]=1;g[1].push_back(1);}
        }
        vis[start[0]][start[1]][start[2]]=0;
        cout<<bfs()<<endl;
    }
    return 0;
}
双向bfs(690ms)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
#include<cmath>
#include<string>
#include<vector>
#include<map>
#include<stack>
#include<queue>
#define INF 0x3f3f3f3f
#define mod 1000000007
#define MAXN 16
#define end END
typedef long long ll;
using namespace std;
int r,c,n;
string maze[MAXN];
int vis[MAXN*MAXN][MAXN*MAXN][MAXN*MAXN];///标记判重数组
int vis1[MAXN*MAXN][MAXN*MAXN][MAXN*MAXN];
int dx[]={
    
    1,-1,0,0,0};
int dy[]={
    
    0,0,1,-1,0};
int start[3],end[3];
vector<int> g[MAXN*MAXN];
int getid(int a,int b,int c)
{
    
    
    return (a<<16)|(b<<8)|c; ///对状态进行编码
}
bool no(int a,int b,int na,int nb)
{
    
    
    return (na==nb)||(a==nb&&b==na);///判断a和b是否走到同一个位置或位置交换了
}
int bfs()
{
    
    
    queue<int> q1,q2;
    q1.push(getid(start[0],start[1],start[2]));
    q2.push(getid(end[0],end[1],end[2]));
    vis[start[0]][start[1]][start[2]]=0;
    vis1[end[0]][end[1]][end[2]]=0;
    while(!q1.empty()&&!q2.empty())
    {
    
    
        int cur=q1.front();q1.pop();
        int a=(cur>>16)&0xff,b=(cur>>8)&0xff,c=cur&0xff;///解码
        for(int i=0;i<g[a].size();++i)
        {
    
    
            int na=g[a][i];
            for(int j=0;j<g[b].size();++j)
            {
    
    
                int nb=g[b][j];
                if(!no(a,b,na,nb))
                for(int k=0;k<g[c].size();++k)
                {
    
    
                    int nc=g[c][k];
                    if(no(a,c,na,nc)||no(b,c,nb,nc))continue;
                    if(vis[na][nb][nc]!=-1)continue;
                    q1.push(getid(na,nb,nc));
                    vis[na][nb][nc]=vis[a][b][c]+1;
                }
            }
        }
        int cur1=q2.front();q2.pop();
        int A=(cur1>>16)&0xff,B=(cur1>>8)&0xff,C=cur1&0xff;
        for(int i=0;i<g[A].size();++i)
        {
    
    
            int na=g[A][i];
            for(int j=0;j<g[B].size();++j)
            {
    
    
                int nb=g[B][j];
                if(!no(A,B,na,nb))
                for(int k=0;k<g[C].size();++k)
                {
    
    
                    int nc=g[C][k];
                    if(no(A,C,na,nc)||no(B,C,nb,nc))continue;
                    if(vis1[na][nb][nc]!=-1)continue;
                    q2.push(getid(na,nb,nc));
                    vis1[na][nb][nc]=vis1[A][B][C]+1;
                    if(vis[na][nb][nc]!=-1)return vis1[na][nb][nc]+vis[na][nb][nc];
                }
            }
        }
    }
    return -1;
}
int main()
{
    
    
    //ios::sync_with_stdio(false);
    while(cin>>c>>r>>n&&(r||c||n))
    {
    
    
        memset(vis,-1,sizeof(vis));
        memset(vis1,-1,sizeof(vis1));
        char ch=getchar();
        for(int i=0;i<r;++i)
            getline(cin,maze[i]);
        for(int i=0;i<MAXN*MAXN;++i)g[i].clear();
        for(int i=0;i<r;++i)
        {
    
    
            for(int j=0;j<c;++j)
            {
    
    
                int cur=i*c+j;
                if(isupper(maze[i][j]))end[maze[i][j]-'A']=cur;///初始
                if(islower(maze[i][j]))start[maze[i][j]-'a']=cur;///目标
                if(maze[i][j]!='#')
                for(int k=0;k<5;k++)
                {
    
    
                    int nx=i+dx[k],ny=j+dy[k];
                    if(maze[nx][ny]!='#')
                    {
    
    
                        int next=nx*c+ny;
                        g[cur].push_back(next);///存放这个点的下一个可达的点
                    }
                }
            }
        }
        if(n<3)
        {
    
    
            start[2]=end[2]=0;g[0].push_back(0);
            if(n<2){
    
    start[1]=end[1]=1;g[1].push_back(1);}
        }
        cout<<bfs()<<endl;
    }
    return 0;
}

A*(450ms)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=16+2;
struct E {
    
    int v,nxt;} e[1000000];
int rt[N][N],d[200][200][200],h[3][200],n,m,k,tot,ne,hd[200],bg[3],ed[3];
char s[N][N];
struct D {
    
    
    int a[3];
    bool operator<(const D& b)const {
    
    
        return d[a[0]][a[1]][a[2]]+max(h[0][a[0]],max(h[1][a[1]],h[2][a[2]]))
               >d[b.a[0]][b.a[1]][b.a[2]]+max(h[0][b.a[0]],max(h[1][b.a[1]],h[2][b.a[2]]));
    }
};
void addedge(int u,int v) {
    
    e[ne]= {
    
    v,hd[u]},hd[u]=ne++;}
bool ok(int* u,int* v) {
    
    
    if(v[0]==v[1]||v[1]==v[2]||v[2]==v[0])return 0;
    if(u[0]==v[1]&&u[1]==v[0])return 0;
    if(u[1]==v[2]&&u[2]==v[1])return 0;
    if(u[2]==v[0]&&u[0]==v[2])return 0;
    return 1;
}

void bfs(int S,int* d) {
    
    
    int u,v;
    queue<int> q;
    for(int i=0; i<tot; ++i)d[i]=-1;
    q.push(S),d[S]=0;
    while(!q.empty()) {
    
    
        u=q.front(),q.pop();
        for(int i=hd[u]; ~i; i=e[i].nxt) {
    
    
            v=e[i].v;
            if(!~d[v])d[v]=d[u]+1,q.push(v);
        }
    }
}

int Astar() {
    
    
    int u[3],v[3];
    priority_queue<D> q;
    d[bg[0]][bg[1]][bg[2]]=0,q.push({
    
    bg[0],bg[1],bg[2]});
    while(!q.empty()) {
    
    
        memcpy(u,q.top().a,sizeof u),q.pop();
        if(u[0]==ed[0]&&u[1]==ed[1]&&u[2]==ed[2])return d[u[0]][u[1]][u[2]];
        for(int i=hd[u[0]]; ~i; i=e[i].nxt)
            for(int j=hd[u[1]]; ~j; j=e[j].nxt)
                for(int k=hd[u[2]]; ~k; k=e[k].nxt) {
    
    
                    v[0]=e[i].v,v[1]=e[j].v,v[2]=e[k].v;
                    if(ok(u,v)&&!~d[v[0]][v[1]][v[2]]) {
    
    
                        d[v[0]][v[1]][v[2]]=d[u[0]][u[1]][u[2]]+1;
                        q.push({
    
    v[0],v[1],v[2]});
                    }
                }
    }
    return -1;
}

int main() {
    
    
    while(scanf("%d%d%d",&m,&n,&k)&&n) {
    
    
        scanf(" ");
        memset(hd,-1,sizeof hd),ne=0,tot=3;
        for(int i=0; i<3; ++i)bg[i]=ed[i]=i;
        addedge(0,0),addedge(1,1),addedge(2,2);
        for(int i=0; i<n; ++i)gets(s[i]);
        for(int i=1; i<n-1; ++i)for(int j=1; j<m-1; ++j)if(s[i][j]!='#') {
    
    
                    rt[i][j]=tot++;
                    addedge(rt[i][j],rt[i][j]);
                    if(s[i-1][j]!='#') {
    
    
                        addedge(rt[i][j],rt[i-1][j]);
                        addedge(rt[i-1][j],rt[i][j]);
                    }
                    if(s[i][j-1]!='#') {
    
    
                        addedge(rt[i][j],rt[i][j-1]);
                        addedge(rt[i][j-1],rt[i][j]);
                    }
                    if(isupper(s[i][j]))bg[s[i][j]-'A']=rt[i][j];
                    else if(islower(s[i][j]))ed[s[i][j]-'a']=rt[i][j];
                }
        for(int i=0; i<tot; ++i)for(int j=0; j<tot; ++j)for(int k=0; k<tot; ++k)d[i][j][k]=-1;
        for(int i=0; i<3; ++i)bfs(ed[i],h[i]);
        printf("%d\n",Astar());
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43638337/article/details/100606183