題目大意:同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;
}