HDU 1043——八數碼的多種解題思路(持續更新)

fengyuzhicheng發表於2018-03-01

八數碼算是一個比較經典的搜尋問題了。

hdu 1043: http://acm.hdu.edu.cn/showproblem.php?pid=1043

poj 1077:  http://poj.org/problem?id=1077

1.樸素廣搜+雜湊:

#include <cstdio>
#include <string>
#include <queue>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

struct Node {
	int s[9];
	int loc;
	int status;
};
queue<Node> q;
struct Path {
    int fa;
    char d;
};
Path path[500000];
string s,_ans;
int a[10],F[10];
int jud[500000];
int dir_jud[4][9] = {
	//rlud
	1,1,0,1,1,0,1,1,0,
	0,1,1,0,1,1,0,1,1,
	0,0,0,1,1,1,1,1,1,
	1,1,1,1,1,1,0,0,0
};
int dir[4] ={1,-1,-3,3};
char zifu[10] = {"rlud"};

int Cantor(int a[]) {
	int ans = 0;
	for (int i = 0; i < 9; i++) {
		int t = 0;
		for (int j = 0; j < i; j++) {
			if(a[j]<a[i]) t++;
		}
		ans+=(a[i]-t-1)*F[9-i-1];
	}
	return ans;
}
void read(){
	int j = 0;
	for (int i = 0; i < s.size(); i++) {
		if(s[i]>='1'&&s[i]<='9') {
			a[j++] = s[i]-'0';
		}
		else if(s[i]=='x') {
			a[j++] = 9;
		}
	}
}
int check(int a[]) {
	int ans = 0;
	for (int i = 0; i < 9; i++) {
		for (int j = 0; j < i; j++) {
			if(a[i]<a[j]&&a[j]!=9) ans++;
		}
	}
	return ans;
}
void cal(){
	F[0] = 1;
	for (int i = 1; i <= 9; i++)
		F[i] = i*F[i-1];
}

int bfs(){
	while(!q.empty()){
        if (!q.front().status) return 1;
        for (int i = 0; i < 4; i++) {           
			Node tt = q.front();
			if (dir_jud[i][tt.loc]) {
                swap(tt.s[tt.loc],tt.s[tt.loc+dir[i]]);
                tt.status = Cantor(tt.s);
                if (!jud[tt.status]) {
                    jud[tt.status] = 1;
                    path[tt.status].fa = q.front().status;
                    path[tt.status].d = zifu[i];
                    tt.loc += dir[i];
                    q.push(tt);
                }
			}
		}
		q.pop();
	}
    return 0;
}
int main(){
	while(getline(cin,s)){
        q = queue<Node> ();
		memset(path,0,sizeof(path));
        memset(jud,0,sizeof(jud));
		read();cal();
		if(check(a)%2) {
			puts("unsolvable");
			continue;
		}    
		Node start;
		for(int i = 0; i < 9; i++) {
			start.s[i] = a[i];
			if(a[i]==9)start.loc = i;
		}
		start.status = Cantor(start.s);
		q.push(start);
		path[start.status].fa = -1;
        jud[start.status] = 1;        
		if(!bfs()) {
			puts("unsolvable");
			continue;
		}
        int i = 0;
        while (path[i].fa!=-1) {
            _ans.push_back(path[i].d);
            i = path[i].fa;
        }
        reverse(_ans.begin(),_ans.end());
        cout << _ans << endl;
	}
	return 0;
}
2.廣搜打表+雜湊
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring> 
#include <algorithm>
#include <queue>
#define MAXN 362880
using namespace std;
int a[10];
char s[1000];
int F[10];
struct Node{
	int s[9];
	int zero;
	int status;
};
queue<Node> q;
struct Path{
	int fa;
	char d;
};
Path path[MAXN];
bool jud[MAXN];
//rlud
char z[10] = {"lrdu"};
int dir[4] = {1,-1,-3,3};
bool pre_d[4][9] = {
	1,1,0,1,1,0,1,1,0,
	0,1,1,0,1,1,0,1,1,
	0,0,0,1,1,1,1,1,1,
	1,1,1,1,1,1,0,0,0
};
int Cantor(int c[]) {
	int ans = 0;
	for (int i = 0;i < 9; i++) {
		int t = 0;
		for (int j = 0; j < i; j++) {
			if (c[j]<c[i]) t++;
		}
		ans+=F[9-i-1]*(c[i]-t-1);
	}
	return ans;
}

void bfs() {
	while (!q.empty()) {
		for (int i = 0; i < 4; i++) {
			Node t = q.front();
			if(pre_d[i][t.zero]==1) {
				swap(t.s[t.zero], t.s[t.zero+dir[i]]);
				t.status = Cantor(t.s);
				if(jud[t.status]==0) {
					jud[t.status] = 1;
					t.zero += dir[i];
					path[t.status].fa = q.front().status;
					path[t.status].d = z[i];
					q.push(t);
				}
			}	
		}
		q.pop();
	}
}

int main() {
	F[0] = 1;
	for (int i = 1; i < 9; i++) F[i] = F[i-1]*i;
	Node start;
	for (int i = 0; i < 9; i++) start.s[i] = i+1;
	start.zero = 8;
	start.status = 0;
	jud[0] = 1;
	path[0].fa = -1;
	q.push(start);
	bfs();
	while(cin.getline(s,1000)){
		int j = 0;
		for (int i = 0; i < strlen(s); i++) {
			if(s[i]<='9'&&s[i]>='1') a[j++] = s[i]-'0';
			else if (s[i]=='x') a[j++] = 9;
		}
		int ans = Cantor(a);
		if(jud[ans]==0) {
			puts("unsolvable");
		}
		else{		
			while(path[ans].fa!=-1) {
				printf("%c",path[ans].d);
				ans=path[ans].fa;
			}
			printf("\n");
		}
	  }
	return 0;
}

3.雙向廣搜

// #include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <queue>

using namespace std;
char s[1000];
string ANS[2];
int f[10];
int a[10];
char z[2][10] = {"lrud","rldu"};
int dir[4] = {1,-1,3,-3};
int p_dir[4][9] = {
	1,1,0,1,1,0,1,1,0,
	0,1,1,0,1,1,0,1,1,
	1,1,1,1,1,1,0,0,0,
	0,0,0,1,1,1,1,1,1
};
struct Node {
	int zero, status;
	int s[9];
	Node(){};
	Node(int Z,int S){
		zero = Z, status = S;
	}
};
struct Path {
	int fa; char c;
	Path(){};
	Path(int FA,int C) {
		fa = FA, c = C;
	}
};
Path path[400000];
queue<Node> q[2];
int jud[400000];

int Cantor(int a[]) {
	int ans = 0;
	for (int i = 0; i < 9; i++) {
		int t = 0;
		for (int j = 0; j < i; j++)
			if (a[i]>a[j]) t++;
			ans+=f[9-i-1]*(a[i]-1-t);
	}
	return ans;
}
int ca;
void dbfs(){
	while (!q[0].empty()&&!q[1].empty()) {
		for (int j = 0; j < 2; j++) {
			for (int i = 0; i < 4; i++) {
				if (p_dir[i][q[j].front().zero]) {
					Node t = q[j].front();
					swap(t.s[t.zero],t.s[t.zero+dir[i]]);
					t.status = Cantor(t.s);
					if (!jud[t.status]) {
						path[t.status].fa = q[j].front().status;
						path[t.status].c = z[j][i];
						jud[t.status] = j+1;
						t.zero += dir[i];
						q[j].push(t);
					}
					else{
						if (jud[t.status]==2-j) {
							int t1 = q[j].front().status; 
							int t2 = t.status;
							ANS[j]+=z[j][i];
							while (path[t1].fa!=-1) {
								ANS[j]+=path[t1].c;
								t1 = path[t1].fa;
							}
							while (path[t2].fa!=-1) {
								ANS[1-j]+=path[t2].c;
								t2 = path[t2].fa;
							}
							reverse(ANS[1].begin(),ANS[1].end());
							cout << ANS[1]<<ANS[0]<<endl;
							return;
						}
					}
				}
			}
			q[j].pop();	
		}	
	}
	puts("unsolvable");
}
int check(int a[]) {
	int ans = 0;
	for (int i = 0; i < 9; i++) {
		for (int j = 0; j < i; j++) {
			if(a[i]<a[j]&&a[j]!=9) ans++;
		}
	}
	return ans;
}
int main() {
	f[0] = 1;
	for (int i = 1; i < 10; i++) f[i] = f[i-1]*i;
	while(cin.getline(s, 1000)) {
		memset(path,0,sizeof(path));
		memset(jud,0,sizeof(jud));
		q[0] = q[1] = queue<Node>();
		ANS[0].clear();ANS[1].clear();
		int j = 0, t = 0;
 		for (int i = 0; i < strlen(s); ++i) {
			if (s[i]<='8'&&s[i]>='1') {
				a[j++] = s[i]-'0';
			}
			else if (s[i]=='x'){
				a[j++] = 9;
				t = j-1;
			}
		}
		if(check(a)%2) {
			puts("unsolvable");
			continue;
		}
		int ans = Cantor(a);
		q[1].push(Node(t,ans));
		q[0].push(Node(8,0));
		for (int i = 0 ; i < 9; i++) {
			q[0].front().s[i] = i+1;
			q[1].front().s[i] = a[i];
		}
		path[0].fa = path[ans].fa= -1;
		jud[0] = 1;
		jud[ans] = 2;
		dbfs();
	}
	return 0;
}


注:這題資料好像挺水的,poj無unslovable資料,另外以提交結果看,雙向廣搜並不快(才不是寫的蠢) 


相關文章