题目:http://poj.org/problem?id=1077
用数字0代表X,放在数组里,康拓展开求状态值肯定不重叠,因为本身就是排列
A*:估价函数为每个数到它该在位置(目标状态)的距离之和
3 | 1 | 2 | -> | 1 | 2 | 3 |
4 | 6 | 5 | -> | 4 | 5 | 6 |
0 | 8 | 7 | -> | 7 | 8 | 0 |
估价值:
2 + 1 + 1 + 0 + 1 + 1 + 2+ 0 + 2 = 10
值越小,说明该状态离目标状态最近。虽然这个启发函数不完美,误判的情况很多,但是它能提高搜索效率
此外先不考虑X,求1-8的逆序数,如果逆序数是奇数就不可解,因为交换数字,不改变逆序数的奇偶性,而最终状态逆序数是0(偶数)。
自己的证明:
空格与左右棋子交换不会改变棋子数列的逆序数,因为数列并没有改变。
1 5 4
3 2 6
7 8 X
假设交换X和6,则6对7,8的逆序数各加1,加了偶数个(X的逆序数是不考虑的)。同理,X跟下面的交换逆序数-2,逆序数是偶数的依旧是偶数,不改变逆序数的奇偶性。
//POK 0MS HDU 734MS
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define INF 0x7F7F7F7F
#define eps 10^(-6)
#define MEM(a) memset(a,0,sizeof(a));
#define FOR(i,n) for(int i=0;i<n;i++)
#define FIN freopen("in.txt","r",stdin);
#define FOUT freopen("out.txt","w",stdout); //右+1,下:+3,上-3,左-1
#define Max 366666
int a[4]={-3,-1,1,3},n,m,visit[Max],tp[Max],s_state;
int fac[]={1,1,2,6,24,120,720,5040,40320,362880};
int aim[9]; //aim[i]:目标状态i位置的数
int end_aim;
struct node
{//state为状态值,由康拓展开计算,x为X的位置,pos为被交换数的位置
int x,state,ss[9],pos;
int f,g,h;//估价值
bool operator < (const node &Another)const
{
return f > Another.f;//小值优先
}
};
struct save
{
int pre,dir;//方向和父节点
}path[Max];
priority_queue<node> q;
char change(int dir);
int cantor(int s[]) //康拓保存状态
{
int temp,i,j,res=0;
for(i = 0; i < 9; i++)
{
temp = 0;
for(j = i + 1; j < 9; j++)
if(s[j] < s[i])
temp++;
res += temp*fac[8-i];
}
return res+1;
}
void print1(int state)
{
int num = 0,i;
while(state != s_state )
{
tp[num++]=change(path[state].dir);
state=path[state].pre;
}
for( i=num-1; i>=0; i--)
printf("%c",tp[i]);
}
char change(int dir) //右+1,下:+3,上-3,左-1
{
if( dir == -3) return 'u';
if( dir == -1) return 'l';
if( dir == 1) return 'r';
if( dir == 3) return 'd';
}
int count_h(int cur[]) //该数和它本该在的位置的距离
{
int dis = 0;
for(int i = 0; i <= 8; i++)
{
if(cur[i] != 0)
dis += abs(cur[i] - (i+1));
else
dis += 9-(i+1);
}
return dis;
}
int AStar(int s[])
{
node t,cur;
int i,temp,k;
while(!q.empty()) q.pop();
memset(visit,0,sizeof(visit));
for(i = 0; i <= 8; i++)
{
t.ss[i] = s[i];
if(s[i] == 0)
t.x = i;
}
t.state = cantor(t.ss);
visit[t.state] = 1;
path[t.state].pre = -1;
t.f = count_h(s);
q.push(t);
s_state = t.state; //起始状态值,用于打印路径
while( !q.empty() )
{
t = q.top();
q.pop();
if( t.state == end_aim )
{
print1(t.state);
putchar('\n');
return 1;
}
for(i = 0; i < 4; i++)
{
cur.pos = t.x + a[i];
if(a[i] == 1 && (t.x+1)%3==0 )
continue; //一位数组转行处理
if(a[i] == -1 && t.x%3==0 )
continue;
if( cur.pos >=0 && cur.pos <=8 )
{
for(k=0;k<=8;k++) //copy原状态数字
cur.ss[k] = t.ss[k];
{ //交换
temp = cur.ss[t.x];
cur.ss[t.x] = cur.ss[cur.pos];
cur.ss[cur.pos] = temp;
}
cur.x = cur.pos;
cur.state = cantor(cur.ss);
cur.f = count_h(cur.ss);
if( !visit[cur.state] )
{
path[cur.state].dir = a[i];
path[cur.state].pre = t.state;
visit[cur.state] = 1;
q.push(cur);
}
}
}
}
return 0;
}
int check(int s[]) //忽视x,求逆序数
{
int i,j,cnt=0;
for(i=0;i<=8;i++)
{
if(s[i]==0) continue;
for(j=0;j<i;j++)
{
if(s[j]==0) continue;
if(s[j]>s[i]) cnt++;
}
}
return cnt;
}
int main()
{
int i,j,ok,s[10];
char str[30];
// FIN
for(int i = 0; i < 8; i++)
aim[i] = i + 1;
aim[8] = 0; //目标状态
end_aim = cantor(aim);
while(gets(str))
{
j=0;
for(i=0; str[i]; i++)
{ //X用0代表
if(str[i] >= '1' && str[i] <= '8')
s[j++] = str[i]-'0';
else if(str[i] == 'x') s[j++]=0;
}
if(check(s)%2)
puts("unsolvable");
else
{
ok = AStar(s);
if(!ok)
puts("unsolvable");
}
}
return 0;
}
双向BFS(HDU会TLE)
// 32MS
#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std; //右+1,下:+3,上-3,左-1
#define Max 366666
int a[4]={-3,-1,1,3},n,m,vist1[Max],vist2[Max],tp[Max], s_state;
int fac[]={1,1,2,6,24,120,720,5040,40320,362880};
typedef struct
{
int x,state,ss[9],pos;
}node;
struct save
{
int pre,dir;
}path1[Max],path2[Max];
queue <node> p,q;
char change(int dir);
char change2(int dir);
int cantor(int s[])
{
int temp,i,j,res=0;
for(i=0;i<9;i++)
{
temp = 0;
for(j=i+1;j<9;j++)
if(s[j] < s[i])
temp++;
res+=temp*fac[8-i];
}
return res+1;
}
void print1(int state)
{
int num=0,i;
while(state != s_state )
tp[num++]=change(path1[state].dir), state=path1[state].pre;
for( i=num-1; i>=0; i--) printf("%c",tp[i]);
}
void print2(int state)
{
while(path2[state].pre != -1 )
{
printf("%c",change2(path2[state].dir));
state = path2[state].pre;
}
}
char change2(int dir) //右+1,下:+3,上-3,左-1
{
if( dir == -3) return 'd';
if( dir == -1) return 'r';
if( dir == 1) return 'l';
if( dir == 3) return 'u';
}
char change(int dir) //右+1,下:+3,上-3,左-1
{
if( dir == -3) return 'u';
if( dir == -1) return 'l';
if( dir == 1) return 'r';
if( dir == 3) return 'd';
}
int bfs(int s[])
{
node t,cur;
int i,temp,k;
while(!q.empty()) q.pop();
while(!p.empty()) p.pop();
memset(vist1,0,sizeof(vist1));
memset(vist2,0,sizeof(vist2));
for(i=0;i<=8;i++)
{
t.ss[i] = s[i];
if(s[i] == 0)
t.x = i;
}
t.state = cantor(t.ss);
vist1[t.state] = 1;
path1[t.state].pre = -1;
q.push(t);
s_state = t.state;
for(i=0;i<8;i++)
t.ss[i] = i+1;
t.ss[8] = 0;
t.x = 8;
t.state = cantor(t.ss);
vist2[t.state] = 1;
path2[t.state].pre = -1;
p.push(t);
while( !q.empty() && !p.empty() )
{
if(!q.empty())
{
t=q.front();
q.pop();
for(i=0;i<4;i++)
{
cur.pos = t.x + a[i];
if(a[i] == 1 && (t.x+1)%3==0 )
continue;
if(a[i] == -1 && t.x%3==0 )
continue;
if( cur.pos >=0 && cur.pos <=8 )
{
for(k=0;k<=8;k++)
cur.ss[k] = t.ss[k];
{
temp = cur.ss[t.x];
cur.ss[t.x] = cur.ss[cur.pos];
cur.ss[cur.pos] = temp;
}
cur.x = cur.pos;
cur.state = cantor(cur.ss);
if( !vist1[cur.state] )
{
path1[cur.state].dir = a[i];
path1[cur.state].pre = t.state;
vist1[cur.state] = 1;
q.push(cur);
}
if( vist2[cur.state] )
{
print1(cur.state);
print2(cur.state);
putchar('\n');
return 1;
}
}
}
}
if(!p.empty())
{
t=p.front();
p.pop();
for(i=0;i<4;i++)
{
cur.pos = t.x + a[i];
if(a[i] == 1 && (t.x+1)%3==0 )
continue;
if(a[i] == -1 && t.x%3==0 )
continue;
if( cur.pos >=0 && cur.pos <=8 )
{
for(k=0;k<=8;k++)
cur.ss[k] = t.ss[k];
{
temp = cur.ss[t.x];
cur.ss[t.x] = cur.ss[cur.pos];
cur.ss[cur.pos] = temp;
}
cur.x = cur.pos;
cur.state = cantor(cur.ss);
if( !vist2[cur.state] )
{
path2[cur.state].dir = a[i];
path2[cur.state].pre = t.state;
vist2[cur.state] = 1;
p.push(cur);
}
if( vist1[cur.state] )
{
print1(cur.state);
print2(cur.state);
putchar('\n');
return 1;
}
}
}
}
}
return 0;
}
int main()
{
int i,j,ok,s[10];
char str[30];
// freopen("a.txt","r",stdin);
while(gets(str))
{
j=0;
for(i=0; str[i]; i++)
{
if(str[i]>='1'&&str[i]<='8')
s[j++]=str[i]-'0';
else if(str[i]=='x') s[j++]=0;
}
ok=bfs(s);
if(!ok) puts("unsolvable");
}
return 0;
}