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 ;
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章