HDU 1813 Escape from Tetris (IDA*)

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1813

 

题意:给你一个n*n的迷宫,其中0代表有一个人在这个位置,1代表墙,现在要求一个路线,使所有的人通过这个路线都可以走到迷宫的边界

注意当到达边界就相当于出去了不用继续走了,一个格子可以容纳很多人。

题解:先用BFS求出迷宫内部的点走到边界的最小步数(为了后面的IDA*剪枝),因为有很多状态,不好表示,所以可以想到用IDA*算法,在dfs的时候每次内部的点安同一个方向走,当某个点走到边界或遇见墙时不变,其他的点还是继续走。

 

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <list>
#include <deque>
#include <queue>
#include <iterator>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <cctype>
using namespace std;

#define si1(a) scanf("%d",&a)
#define si2(a,b) scanf("%d%d",&a,&b)
#define sd1(a) scanf("%lf",&a)
#define sd2(a,b) scanf("%lf%lf",&a,&b)
#define ss1(s)  scanf("%s",s)
#define pi1(a)    printf("%d\n",a)
#define pi2(a,b)  printf("%d %d\n",a,b)
#define mset(a,b)   memset(a,b,sizeof(a))
#define forb(i,a,b)   for(int i=a;i<b;i++)
#define ford(i,a,b)   for(int i=a;i<=b;i++)

typedef long long LL;
const int N=11;
const int INF=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-7;

int n,depth;
int cnt;//表示不是边界点的个数
int x[101],y[101];//存放不是边界的点
int xh[N][N];//xh[i][j]表示ij到边界的最短距离,由BFS生成
char str[N][N];
int ans[1000];//存放方向
int dir[4][2]={0,1,-1,0,1,0,0,-1};//east north south west 按照字典序
bool flag;

struct node
{
    int x,y;
}w,e;

bool bianjie(int x,int y)
{
    if(x==0||x==n-1||y==0||y==n-1)
        return true;
    return false;
}

bool inmap(int x,int y)
{
    if(x>=0&&x<n&&y>=0&&y<n)
        return true;
    return false;
}

void bfs()
{
    queue<node> q;
    q.push(w);
    xh[w.x][w.y]=0;
    while(!q.empty())
    {
        e=q.front();
        q.pop();

        for(int i=0;i<4;i++)
        {
            w.x=e.x+dir[i][0];
            w.y=e.y+dir[i][1];
            if(inmap(w.x,w.y)&&str[w.x][w.y]=='0')
            {
                if(xh[w.x][w.y]<=xh[e.x][e.y]) continue;
                xh[w.x][w.y]=xh[e.x][e.y]+1;
                q.push(w);
            }
        }
    }
}

int geth(int x[],int y[])//统计最大的距离
{
    int ss=0;
    forb(i,0,cnt)   ss=max(ss,xh[x[i]][y[i]]);
    return ss;
}

void dfs(int tx[],int ty[],int de)
{
    if(flag)    return ;
    if(geth(tx,ty)>de)  return ;
    if(de==0)//或者geth(tx,ty)==0
    {
        flag=true;
        return ;
    }
    for(int i=0;i<4;i++)
    {
        int xx[101],yy[101];
        for(int j=0;j<cnt;j++)//不是边界的点都按照i这个方向走
        {
            xx[j]=tx[j];    yy[j]=ty[j];
            if(bianjie(xx[j],yy[j]))    continue;
            if(str[xx[j]+dir[i][0]][yy[j]+dir[i][1]]=='0')
            {
                xx[j]+=dir[i][0];
                yy[j]+=dir[i][1];
            }
        }
        ans[de]=i;
        dfs(xx,yy,de-1);
        if(flag)    return;//这个地方一定要加上这一句,不然会被覆盖
    }
}

void IDA()
{
    flag=false;
    depth=geth(x,y);
    while(1)
    {
        dfs(x,y,depth);
        if(flag)
        {
            for(int i=depth;i>0;i--)
            {
                if(ans[i]==0)   puts("east");
                if(ans[i]==1)   puts("north");
                if(ans[i]==2)   puts("south");
                if(ans[i]==3)   puts("west");
            }
            break;
        }
        depth++;
    }
}

int main()
{
//    freopen("input.txt","r",stdin);
    int ca=0;
    while(~si1(n))
    {
        forb(i,0,n) ss1(str[i]);
        mset(xh,INF);//初始化为无穷大
        cnt=0;
        forb(i,0,n)
            forb(j,0,n)
                if(str[i][j]=='0')
                {
                    w.x=i;  w.y=j;
                    if(!bianjie(i,j))
                    {
                        x[cnt]=i;
                        y[cnt]=j;
                        cnt++;
                    }
                    else
                        bfs();//求出每个点要走出去的最小步数
                }
        if(ca++)    printf("\n");
        if(cnt==0||geth(x,y)==INF)  {continue;}//都是边界点|走不出去的情况

        IDA();
    }
    return 0 ;
}


 

你可能感兴趣的:(IDA)