HDU 1043 Eight

題目大意:同POJ 1077 Eight相同,只不過有多個測例(以EOF結束)

題目鏈接

雙向廣搜:

註釋代碼:

/*                                 
 * Problem ID : HDU 1043 Eight
 * Author     : Lirx.t.Una                                 
 * Language   : C++                     
 * Run Time   : 1109 ms                                 
 * Run Memory : 3212 KB                                 
*/ 

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <bitset>
#include <queue>
#include <stack>

//表示搜索的兩頭first和second
//first從起始往目標搜
//second從目標往起始搜
#define FST        0
#define SEC        1

//存儲狀態字符串的長度
#define	STRLEN      10
//結束臨時輸入的行
#define	FMTLEN		20
//結果字符串的最大長度
#define	PATHLEN		25

#define	MAXFAC	362880

using namespace std;

struct    Node { int fath, mov; };//每個結點中存儲父結點下標以及從父結點到子結點的走法
//從起點搜到目標mov表示從父結點到子結點的走法,但是由於從目標搜到起始是反向的,因此此時
//mov表示從子結點走到父結點的走法

Node    node[MAXFAC];

int        FC[9] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320 };

//fac_end,fend[0]表示FST搜索的終點,fend[1]表示SEC搜索的終點
//中間用cat連接,char cat在後面聲明,即concatenate的意思
int        fend[2];
int        fini;//fac_ini,起始狀態傳的fac

char    path[PATHLEN];//最終路徑
char    fmt[FMTLEN];//格式字符串用於接收輸入的內容

char    sini[STRLEN];//起始狀態串
//在雙向廣搜中使用到的父狀態字符串和子狀態字符串
char    sf[STRLEN];//str_father
char    sc[STRLEN];//str_child

char     dx[4] = {  0, 0, -1, 1 };
char     dy[4] = { -1, 1,  0, 0 };
char     mv[4] = { 'l', 'r', 'u', 'd' };
char    _mv[4] = { 'r', 'l', 'd', 'u' };//表示反向移動

char    cat;

bool
cnsov(char *s) {

    int        i, j;
    int        ord;

    for ( ord = 0, i = 0; i < 8; i++ )
        if ( '9' != s[i] )
            for ( j = i + 1; j < 9; j++ )
                if ( '9' != s[j] && s[i] > s[j] )
                    ord++;

    if ( ord % 2 ) return false;    
    return true;
}

int
hash(char *s) {

    int        i, j;
    int        ord;
    int        fac;

    for ( fac = 0, i = 0; i < 8; i++ ) {

        for ( ord = 0, j = i + 1; j < 9; j++ )
            if ( s[i] > s[j] )
                ord++;

        fac += FC[ s[i] - '1' ] * ord;
    }

    return fac;
}

void
fndx( char *s, int &x, int &y ) {

    int        i;

    for ( i = 0; '9' != s[i]; i++ );

    x = i / 3;
    y = i % 3;
}

void
swp( char *s, int i, int j ) {

    char    tmp;

    tmp     = s[i];
    s[i] = s[j];
    s[j] = tmp;
}

void
dbfs(void) {//double direction bfs

    //隊列序號,0表示FST,1表示SEC
    int        XqNo, YqNo;//X爲要拓展的隊列,Y不拓展
    int        nf;//int_father,父狀態的int形式
    int        ff, fc;//fac_father、fac_child,父子狀態的fac形式
    int        x, y;//父結點9的位置
    int        xx, yy;//子結點9的位置

    int        i;//計數變量

    //兩個方向搜索的隊列以及是否訪問的位圖
    bitset<MAXFAC + 1>    vis[2];
    queue<int>        que[2];//存放狀態的int形式

    //初始化
    que[FST].push(atoi(sini));
    que[SEC].push(123456789);

    vis[FST][fini] = true;
    vis[SEC][0] = true;

    while (true) {

	//爲了使兩個方向搜索程度趨於平衡,因此挑隊列當前規模較小的一頭進行拓展
        XqNo = que[FST].size() < que[SEC].size() ? FST : SEC;
        YqNo = XqNo ^ 1;//另一頭不擴展

        nf = que[XqNo].front();
        que[XqNo].pop();
        sprintf(sf, "%d", nf); 
        ff = hash(sf);
        fndx(sf, x, y);

        for ( i = 0; i < 4; i++ ) {

            xx = x + dx[i];
            yy = y + dy[i];

            if ( xx < 0 || xx > 2 || yy < 0 || yy > 2 )  
                continue;

            strcpy(sc, sf);  
            swp( sc, 3 * x + y, 3 * xx + yy );
            fc = hash(sc);

            if ( vis[YqNo][fc] ) {//如果當前擴展出來的結點在另一頭中搜索過則表示兩頭可以接上
		//即搜索成功
                    
                fend[XqNo] = ff;
                fend[YqNo] = fc;
                    
                cat = !XqNo ? mv[i] : _mv[i];//中間銜接的走法注意方向,如果當前擴展隊列是FST則順接否則反接
                    
                return ;
            }

            if ( vis[XqNo][fc] ) continue;//檢查是否重複搜索            

            vis[XqNo][fc] = true;//更新信息
            node[fc].fath = ff;
            node[fc].mov  = !XqNo ? mv[i] : _mv[i];//注意是哪一頭            

            que[XqNo].push(atoi(sc));
        }
    }
}

void
make_path(void) {

    int        i;//計數變量
    int        f;//fac遊標

    stack<char>        stk;

    stk.push(cat);//先將銜接值入站,FST一頭需要反推而得
    for ( f = fend[FST]; f != fini; f = node[f].fath )
        stk.push(node[f].mov);

    for ( i = 0; !stk.empty(); i++ ) {

        path[i] = stk.top();
        stk.pop();
    }
    for ( f = fend[SEC]; f; f = node[f].fath )//SEC一頭順推就行了
        path[i++] = node[f].mov;

    path[i] = '\0';//注意細節!!
    puts(path);
}

int
main() {

    
    int        len;
    int        i, j;

    while ( gets(fmt) ) {

        len = strlen(fmt);
        for ( i = 0, j = 0; i < len; i++ ) 
            if ( fmt[i] != ' ' )
                if ( 'x' == fmt[i] ) sini[j++] = '9';
                else sini[j++] = fmt[i];
        sini[j] = '\0';

        if ( !cnsov(sini) ) {

            puts("unsolvable");
            continue;
        }

        fini = hash(sini);
        dbfs();
        make_path();
    }

    return 0;
}
無註釋代碼:

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <bitset>
#include <queue>
#include <stack>

#define FST        0
#define SEC        1

#define	STRLEN      10
#define	FMTLEN		20
#define	PATHLEN		25

#define	MAXFAC	362880

using namespace std;

struct    Node { int fath, mov; };

Node    node[MAXFAC];

int        FC[9] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320 };

int        fend[2];
int        fini;

char    path[PATHLEN];
char    fmt[FMTLEN];

char    sini[STRLEN];
char    sf[STRLEN];
char    sc[STRLEN];

char     dx[4] = {  0, 0, -1, 1 };
char     dy[4] = { -1, 1,  0, 0 };
char     mv[4] = { 'l', 'r', 'u', 'd' };
char    _mv[4] = { 'r', 'l', 'd', 'u' };

char    cat;

bool
cnsov(char *s) {

    int        i, j;
    int        ord;

    for ( ord = 0, i = 0; i < 8; i++ )
        if ( '9' != s[i] )
            for ( j = i + 1; j < 9; j++ )
                if ( '9' != s[j] && s[i] > s[j] )
                    ord++;

    if ( ord % 2 ) return false;    
    return true;
}

int
hash(char *s) {

    int        i, j;
    int        ord;
    int        fac;

    for ( fac = 0, i = 0; i < 8; i++ ) {

        for ( ord = 0, j = i + 1; j < 9; j++ )
            if ( s[i] > s[j] )
                ord++;

        fac += FC[ s[i] - '1' ] * ord;
    }

    return fac;
}

void
fndx( char *s, int &x, int &y ) {

    int        i;

    for ( i = 0; '9' != s[i]; i++ );

    x = i / 3;
    y = i % 3;
}

void
swp( char *s, int i, int j ) {

    char    tmp;

    tmp     = s[i];
    s[i] = s[j];
    s[j] = tmp;
}

void
dbfs(void) {

    int        XqNo, YqNo;
    int        nf;
    int        ff, fc;
    int        x, y;
    int        xx, yy;

    int        i;

    bitset<MAXFAC + 1>    vis[2];
    queue<int>        que[2];

    que[FST].push(atoi(sini));
    que[SEC].push(123456789);

    vis[FST][fini] = true;
    vis[SEC][0] = true;

    while (true) {

        XqNo = que[FST].size() < que[SEC].size() ? FST : SEC;
        YqNo = XqNo ^ 1;

        nf = que[XqNo].front();
        que[XqNo].pop();
        sprintf(sf, "%d", nf); 
        ff = hash(sf);
        fndx(sf, x, y);

        for ( i = 0; i < 4; i++ ) {

            xx = x + dx[i];
            yy = y + dy[i];

            if ( xx < 0 || xx > 2 || yy < 0 || yy > 2 )  
                continue;

            strcpy(sc, sf);  
            swp( sc, 3 * x + y, 3 * xx + yy );
            fc = hash(sc);

            if ( vis[YqNo][fc] ) {
                    
                fend[XqNo] = ff;
                fend[YqNo] = fc;
                    
                cat = !XqNo ? mv[i] : _mv[i];
                    
                return ;
            }

            if ( vis[XqNo][fc] ) continue;            

            vis[XqNo][fc] = true;
            node[fc].fath = ff;
            node[fc].mov  = !XqNo ? mv[i] : _mv[i];            

            que[XqNo].push(atoi(sc));
        }
    }
}

void
make_path(void) {

    int        i;
    int        f;

    stack<char>        stk;

    stk.push(cat);
    for ( f = fend[FST]; f != fini; f = node[f].fath )
        stk.push(node[f].mov);

    for ( i = 0; !stk.empty(); i++ ) {

        path[i] = stk.top();
        stk.pop();
    }
    for ( f = fend[SEC]; f; f = node[f].fath )
        path[i++] = node[f].mov;

    path[i] = '\0';
    puts(path);
}

int
main() {

    
    int        len;
    int        i, j;

    while ( gets(fmt) ) {

        len = strlen(fmt);
        for ( i = 0, j = 0; i < len; i++ ) 
            if ( fmt[i] != ' ' )
                if ( 'x' == fmt[i] ) sini[j++] = '9';
                else sini[j++] = fmt[i];
        sini[j] = '\0';

        if ( !cnsov(sini) ) {

            puts("unsolvable");
            continue;
        }

        fini = hash(sini);
        dbfs();
        make_path();
    }

    return 0;
}

IDA*:

註釋代碼:

/*                                  
 * Problem ID : HDU 1043 Eight 
 * Author     : Lirx.t.Una                                  
 * Language   : GCC                      
 * Run Time   : 265 ms                                  
 * Run Memory : 200 KB                                  
*/ 

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

//IDDFS最大上界
#define INF		100

#define STRLEN		10
#define FMTLEN		20
//搜索深度可能會大於答案的最大長度
#define PATHLEN		30

int		bound;//搜索界限
int		stp;//搜索深度(步數)

char    path[PATHLEN];
char    fmt[FMTLEN];
char    s[STRLEN];//表示整個棋盤的字符串形式

char     mv[5] = { 'l', 'r', 'u', 'd', 0 };  
char    _mv[5] = { 'r', 'l', 'd', 'u', 0 };
char     dx[4] = {  0, 0, -1, 1 };  
char     dy[4] = { -1, 1,  0, 0 };  

char    sx, sy;//x的起始位置

int  
cnsov(char *s) {  
    
    int        i, j;  
    int        ord;  
    
    for ( ord = 0, i = 0; i < 8; i++ )  
        if ( '9' != s[i] )  
            for ( j = i + 1; j < 9; j++ )  
                if ( '9' != s[j] && s[i] > s[j] )  
                    ord++;  
                
    if ( ord & 1 ) return 0;      
    return 1;  
}

int  
h_val(char *s) {//估價函數爲各個點哈密爾頓路徑的之和(除了'x'之外)  
    
    int     i;  
    int     h;  
    int     tmp;
    
    for ( h = 0, i = 0; i < 9; i++ )
        if ( s[i] != '9' ) {
            
            tmp  = s[i] - '1';
            h   += abs(tmp / 3 - i / 3) + abs(tmp % 3 - i % 3);
        }
    
    return h;  
}

void  
swp( char *s, int i, int j ) {  
    
    char    tmp;  
    
    tmp  = s[i];  
    s[i] = s[j];  
    s[j] = tmp;  
}  

int
min( int a, int b ) {

    return a < b ? a : b;
}

int
ida( int x, int y, int pre_i ) {//IDA*
	//pre_i爲到達(x, y)的走法的數組下標

    int		h;//臨時估價值

    int		i;//計數變量

	//兩個臨時界限
    int		tmp_bound;
    int		tmp;

    int		xx, yy;

    if ( ( h = h_val(s) ) + stp > bound ) return h + stp;//越界返回可能的下一次界限

    tmp_bound = INF;
    for ( i = 0; i < 4; i++ ) {
        
        if ( mv[i] == _mv[pre_i] ) continue;//往回走了

        xx = x + dx[i];
        yy = y + dy[i];

        if ( xx < 0 || xx > 2 || yy < 0 || yy > 2 ) continue;  

        swp( s, 3 * x + y, 3 * xx + yy );//生成下一步狀態    
        path[stp++] = mv[i];//記錄
            
		//搜索成功直接返回0覆蓋bound
		//因爲bound必定是>0的,因此取0表示搜索成功
        if ( !strcmp(s, "123456789") ) return path[stp] = '\0';
        if ( !( tmp = ida( xx, yy, i ) ) ) return 0;//繼續往下搜索,如果成功立馬返回0

        tmp_bound = min( tmp_bound, tmp );//可能新界限必定取最小的那個,可以減少搜索步數
        swp( s, 3 * x + y, 3 * xx + yy );//還原現場,搜索本層的下一個狀態
        stp--;
    }

    return tmp_bound;
}

int
main() {

    int        len;
    int        i, j;

    while ( gets(fmt) ) {  

        len = strlen(fmt);  
        for ( i = 0, j = 0; i < len; i++ )   
            if ( fmt[i] != ' ' )  
                if ( 'x' == fmt[i] ) {
                        
                    sx = j / 3;
                    sy = j % 3;
                    s[j++] = '9';
                }                    
                else
                    s[j++] = fmt[i]; 
        s[j] = '\0';
                
        if ( !cnsov(s) ) {  
            
            puts("unsolvable"); 
            continue;  
        }
        
        stp = 0;
        for ( bound = h_val(s); bound; bound = ida( sx, sy, 4 ) );
        puts(path);    
    }  
    
    return 0;
}
無註釋代碼:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define INF		100

#define STRLEN		10
#define FMTLEN		20
#define PATHLEN		30

int		bound;
int		stp;

char    path[PATHLEN];
char    fmt[FMTLEN];
char    s[STRLEN];

char     mv[5] = { 'l', 'r', 'u', 'd', 0 };  
char    _mv[5] = { 'r', 'l', 'd', 'u', 0 };
char     dx[4] = {  0, 0, -1, 1 };  
char     dy[4] = { -1, 1,  0, 0 };  

char    sx, sy;

int  
cnsov(char *s) {  
    
    int        i, j;  
    int        ord;  
    
    for ( ord = 0, i = 0; i < 8; i++ )  
        if ( '9' != s[i] )  
            for ( j = i + 1; j < 9; j++ )  
                if ( '9' != s[j] && s[i] > s[j] )  
                    ord++;  
                
    if ( ord & 1 ) return 0;      
    return 1;  
}

int  
h_val(char *s) {  
    
    int     i;  
    int     h;  
    int     tmp;
    
    for ( h = 0, i = 0; i < 9; i++ )
        if ( s[i] != '9' ) {
            
            tmp  = s[i] - '1';
            h   += abs(tmp / 3 - i / 3) + abs(tmp % 3 - i % 3);
        }
    
    return h;  
}

void  
swp( char *s, int i, int j ) {  
    
    char    tmp;  
    
    tmp  = s[i];  
    s[i] = s[j];  
    s[j] = tmp;  
}  

int
min( int a, int b ) {

    return a < b ? a : b;
}

int
ida( int x, int y, int pre_i ) {

    int		h;

    int		i;

    int		tmp_bound;
    int		tmp;

    int		xx, yy;

    if ( ( h = h_val(s) ) + stp > bound ) return h + stp;

    tmp_bound = INF;
    for ( i = 0; i < 4; i++ ) {
        
        if ( mv[i] == _mv[pre_i] ) continue;

        xx = x + dx[i];
        yy = y + dy[i];

        if ( xx < 0 || xx > 2 || yy < 0 || yy > 2 ) continue;  

        swp( s, 3 * x + y, 3 * xx + yy );    
        path[stp++] = mv[i];
            
        if ( !strcmp(s, "123456789") ) return path[stp] = '\0';
        if ( !( tmp = ida( xx, yy, i ) ) ) return 0;

        tmp_bound = min( tmp_bound, tmp );
        swp( s, 3 * x + y, 3 * xx + yy );
        stp--;
    }

    return tmp_bound;
}

int
main() {

    int        len;
    int        i, j;

    while ( gets(fmt) ) {  

        len = strlen(fmt);  
        for ( i = 0, j = 0; i < len; i++ )   
            if ( fmt[i] != ' ' )  
                if ( 'x' == fmt[i] ) {
                        
                    sx = j / 3;
                    sy = j % 3;
                    s[j++] = '9';
                }                    
                else
                    s[j++] = fmt[i]; 
        s[j] = '\0';
                
        if ( !cnsov(s) ) {  
            
            puts("unsolvable"); 
            continue;  
        }
        
        stp = 0;
        for ( bound = h_val(s); bound; bound = ida( sx, sy, 4 ) );
        puts(path);    
    }  
    
    return 0;
}

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