CDOJ1669 棋盘游戏 [A*]

  这题要用到A*。每个状态N记录个f(N)值,等于从初始状态走到该状态的实际花费g(N)+从该状态到目标状态花费的估计值h(N)。h(N)要小于等于从该状态到目标状态的实际花费。h(N):棋盘上剩余点到出口的曼哈顿距离之和。
  在BFS时,优先考虑f(N)值小的,在f(N)相同时,考虑当前花费g(N)小的。为了每次找到f(N)最小的点,可以用堆(STL中的优先队列)来保存状态。
  状态表示:最多四个棋子,坐标最大是n(n<=6),所以可以用一个整数来表示,相当于n进制数。
  BFS时的状态扩展就很简单了,每个棋子都可向四个方向走一步,判断走的位子是否在棋盘内,是否是空的,是否和其他棋子相邻。每次走后最小的棋后判断是否在出口,是的话就拿掉了。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<deque>
#include<queue>
#include<vector>
using namespace std;

typedef struct{
    int f,num,t;
    int loc[4];
}node;

int check[2000000],n,m,a[8][8],exitloc,mod;

struct cmp{
    bool operator()(const node& a,const node& b){
        if(a.f>b.f) return true;
        if(a.f==b.f && check[a.num]>check[b.num]) return true;
        return false;
    }
};
priority_queue<node,vector<node>,cmp> Q;

int trans(node nd,int m){
    int num=0,i;
    for(i=0; i<m; i++){
        num*=mod;
        num+=nd.loc[i];
    }
    return num;
}

void ini(int n,int m){
    int k=1,i,j;
    for(i=0; i<m; i++) k*=mod;
    for(i=0; i<=k; i++) check[i]=0;
    for(i=0; i<n; i++)
        for(j=0; j<n; j++)
            a[i][j]=0;
}

int H(node nd){
    int i,num=0,k;
    for(i=0; i<m; i++) {
        k=nd.loc[i];
        if(k!=0)
            num+=abs((k-1)/n - (exitloc-1)/n) + abs((k-1)%n - (exitloc-1)%n);
    }
    return num;
}

void BFS(){
    int k,i,j,xx,yy,x,y,min,num2,t;
    node nd,nd2;
    while(!Q.empty()){
        nd=Q.top();
        Q.pop();
        if(check[0]>0)return;
        min=m;
        for(i=0; i<m; i++){
            k=nd.loc[i];
            if(k==0) continue;
            a[(k-1)/n][((k-1)%n)]=i+1;
            if(i+1<min) min=i+1;
        }
        for(i=min-1; i<m; i++){
            k=nd.loc[i];
            xx=(k-1)/n;
            yy=(k-1)%n;
            a[xx][yy]=0;
            for(j=0; j<4; j++){
                x=xx; y=yy;
                if(j==0)
                    x--;
                else if(j==1)
                    x++;
                else if(j==2)
                    y--;
                else if(j==3)
                    y++;
                if(x>=0 && x<n && y>=0 && y<n && a[x][y]==0)
                if((x==0 || a[x-1][y]==0) && (y==0 || a[x][y-1]==0) && (x==n-1 || a[x+1][y]==0) && (y==n-1 || a[x][y+1]==0)){
                    nd2=nd;
                    nd2.loc[i]=x*n+y+1;
                    t=0;
                    if(i==min-1 && x*n+y+1==exitloc) {nd2.loc[i]=0; t=1;}
                    num2=trans(nd2,m);
                    if(check[num2]>0) continue;
                    check[num2]=check[nd.num]+1;
                    nd2.num=num2;
                    nd2.t=nd.t-t;
                    nd2.f=H(nd2)+check[nd2.num];
                    Q.push(nd2);
                }
            }
            a[xx][yy]=i+1;
        }
        for(i=0; i<m; i++){
            k=nd.loc[i];
            if(k==0) continue;
            a[(k-1)/n][((k-1)%n)]=0;
        }
    }
}

int main()
{
    int T,i,j,k;
    char s[10],ch;
    node nd;
    cin>>T;
    while(T--) {
        scanf("%d %d",&n,&m);
        while(!Q.empty())Q.pop();
        mod=n*n+1;
        gets(s);
        for(i=0; i<n; i++)
        {
            gets(s);
            for(j=0; j<n; j++)
                if(s[j]=='x')
                    exitloc = i*n + j + 1;
                else if(s[j]>='1' && s[j]<='0'+m)
                    nd.loc[s[j]-'1'] = i*n + j + 1;
        }
        ini(n,m);
        k=trans(nd,m);
        check[k]=1;
        nd.num=k;
        nd.f=H(nd)+check[nd.num];
        nd.t=m;
        Q.push(nd);
        BFS();
        printf("%d\n",check[0]-1);
    }
    return 0;
}

 

 

posted on 2012-05-18 16:28  Lattexiaoyu  阅读(273)  评论(0编辑  收藏  举报

导航