題意:

給你一個15 puzzle,問你說可不可以解/可解的話,在50步內解出(不用最佳解)

 

解法:

判斷台面可不可解,可以用檯面上的invertion pair以及空位的位置來判斷(可以參考http://www.csie.ntnu.edu.tw/~u91029/StateSpaceSearch.html)
然後找解的話,可以用A*用估價函數讓比較有可能是答案的檯面先做(用priority queue去找目前最佳答案),

至於估價的函數我這邊是用 1)每個人與他位置的距離,以及 2)目前的檯面已經走幾步了去判斷;原本只有用1)結果WA,所以目前的步數還是很重要OAO

程式碼:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define HASH_SIZE 500000
#define HEAP_SIZE 3234567
#define abs(x)( ((x)>0)?(x):-(x) )
struct Hash{
    char board[4][4];
    char step;
    struct Hash *last;
    struct Hash *next;
    int ssss;
}hash[HASH_SIZE],*heap[HEAP_SIZE];
int heapNum;

void input(char board[4][4]){
    int i,j,num;
    for(i=0;i<4;++i){
        for(j=0;j<4;++j){
            scanf("%d",&num);
            board[i][j] = num;
        }
    }
}
int check(char board[4][4]){
    int inversion = 0;
    int a,b,i,j,ii,jj;
    for(a=0;a<16;++a){
        for(b=0;b<a;++b){
            i = a/4, j = a%4;
            ii= b/4, jj= b%4;
            if(board[i][j]&&board[ii][jj]&&board[i][j]<board[ii][jj])
                ++inversion;
            if(board[i][j]==0){
                inversion += i+1;
            }
        }
    }
    return (inversion&1);
}
void boardCpy(char to[4][4],char from[4][4]){
    int i,j;
    for(i=0;i<4;++i){
        for(j=0;j<4;++j){
            to[i][j] = from[i][j];
        }
    }
}
int boardCmp(char A[4][4],char B[4][4]){
    int i,j;
    for(i=0;i<4;++i){
        for(j=0;j<4&&A[i][j]==B[i][j];++j);
        if(j<4)break;
    }
    if(i>=4)return 0;
    return A[i][j] - B[i][j];
}

void whitePos(char board[4][4],int *x,int *y){
    int i,j;
    for(i=0;i<4;++i){
        for(j=0;j<4;++j){
            if(!board[i][j]){
                *x = i;
                *y = j;
                return;
            }
        }
    }
    *x = -1;
    *y = -1;
}

void boardPrint(char board[4][4]){
    int i,j;
    for(i=0;i<4;++i){
        for(j=0;j<4;++j){
            printf("%d%c",board[i][j],(j==3)?'\n':' ');
        }
    }
}
char site[16][2]={
    {3,3},{0,0},{0,1},{0,2},
    {0,3},{1,0},{1,1},{1,2},
    {1,3},{2,0},{2,1},{2,2},
    {2,3},{3,0},{3,1},{3,2},
};
char initialBoard[4][4] = {
    {1,2,3,4},
    {5,6,7,8},
    {9,10,11,12},
    {13,14,15,0},
};
int cpF(struct Hash *cur){
    int i,j,v=0;
    for(i=0;i<4;++i){
        for(j=0;j<4;++j){
            if(cur->board[i][j]){
                v += abs(i-site[(int)cur->board[i][j]][0])+abs(j-site[(int)cur->board[i][j]][1]);
            }
        }
    }
    return 3*v+cur->ssss;
}
void push(struct Hash *node){
    int now = ++heapNum;
    while(now>1 && cpF(node) < cpF(heap[now/2])){
        heap[now] = heap[now/2];
        now /= 2;
    }
    heap[now] = node;
}
struct Hash* pop(){
    struct Hash *re = heap[1];
    struct Hash *node = heap[heapNum--];
    int now = 1,next = 2;
    while(next<=heapNum){
        if(next<heapNum && cpF(heap[next])>cpF(heap[next+1])){
            ++next;
        }
        if(cpF(heap[next])<cpF(node)){
            heap[now] = heap[next];
            now = next;
            next = now*2;
        }else break;
    }
    heap[now] = node;
    return re;
}

int hashFun(char board[4][4]){
    int i,j;
    unsigned int val = 0;
    for(i=0;i<4;++i){
        for(j=0;j<4;++j){
            val = (val<<4) + (val>>4) + board[i][j];
        }
    }
    return val % HASH_SIZE;
}
struct Hash* search(char board[4][4]){
    struct Hash *cur = hash[hashFun(board)].next;
    while(cur != NULL && boardCmp(cur->board,board)!=0){
        cur = cur->next;
    }
    return cur;
}
struct Hash* insert(char board[4][4],char step,struct Hash* last){
    struct Hash *head = &hash[hashFun(board)];
    struct Hash *cur = (struct Hash*)malloc(sizeof(struct Hash));
    boardCpy(cur->board,board);
    cur->last = last;
    cur->step = step;
    cur->next = head->next;
    if(last==NULL)cur->ssss = 0;
    else cur->ssss = last->ssss+1;
    head->next = cur;
    return cur;
}
void initial(){
    int i;
    struct Hash *cur,*tmp;
    for(i=0;i<HASH_SIZE;++i){
        cur = hash[i].next;
        hash[i].next = NULL;
        while(cur!=NULL){
            tmp = cur;
            cur = cur->next;
            free(tmp);
        }
    }
    heapNum = 0;
}
void inQ(char board[4][4],char step,struct Hash *last){
    if(search(board)!=NULL)return;
    struct Hash *cur = insert(board,step,last);
    push(cur);
}
void L(char board[4][4],int x,int y,struct Hash *last){
    if(y<=0)return;
    board[x][y] = board[x][y-1];
    board[x][y-1] = 0;
    inQ(board,'L',last);
    board[x][y-1] = board[x][y];
    board[x][y] = 0;
}
void R(char board[4][4],int x,int y,struct Hash *last){
    if(y>=3)return;
    board[x][y] = board[x][y+1];
    board[x][y+1] = 0;
    inQ(board,'R',last);
    board[x][y+1] = board[x][y];
    board[x][y] = 0;
}
void U(char board[4][4],int x,int y,struct Hash *last){
    if(x<=0)return;
    board[x][y] = board[x-1][y];
    board[x-1][y] = 0;
    inQ(board,'U',last);
    board[x-1][y] = board[x][y];
    board[x][y] = 0;
}
void D(char board[4][4],int x,int y,struct Hash *last){
    if(x>=3)return;
    board[x][y] = board[x+1][y];
    board[x+1][y] = 0;
    inQ(board,'D',last);
    board[x+1][y] = board[x][y];
    board[x][y] = 0;
}
void (*transF[4])(char[4][4],int,int,struct Hash*)={L,R,U,D};
struct Hash* spfa(char board[4][4]){
    initial();
    struct Hash *cur;
    int x,y;
    int i;
    inQ(board,-1,NULL);
    while(1){
        cur = pop();
        if(boardCmp(cur->board,initialBoard)==0){
            return cur;
        }
        whitePos(cur->board,&x,&y);
        for(i=0;i<4;++i){
            transF[i](cur->board,x,y,cur);
        }
    }
    return NULL;
}
void reStep(struct Hash* cur){
    if(cur->step==-1) return;
    reStep(cur->last);
    putchar(cur->step);
}
int main(){
    int t;
    char board[4][4];
    scanf("%d",&t);
    while(t--){
        input(board);
        if(check(board))puts("This puzzle is not solvable.");
        else {
            reStep(spfa(board));
            putchar('\n');
        }
    }
    return 0;
}

arrow
arrow
    全站熱搜

    alan790712 發表在 痞客邦 留言(0) 人氣()