同样是South Central USA 1998的题,POJ和HDU上的数据比较水,用BFS不加任何优化都可以AC,时间一般是三位数左右。而用A*或IDA*则可以把时间控制在10ms左右,甚至0ms!
然而UVa Live上的这道题是多数据的,用IDA*不加优化都会超时。除此之外题目输入输出很严格,case和case之间必须有空行,在最后一组case之后不能有空行,否则会Wrong Answer..
优化很简单,就是在搜索之前就判断一下是否有解。如果除去x之外的数字序列的逆序数是偶数,则有解;否则无解。因为在上下左右移动的过程中,数列的逆序数是不会产生变化的(在纸上画画就知道)。而目标状态的逆序数是偶数的,所以如果当前的数列逆序数是奇数则必定不能转移到目标状态。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int tar[10][2]={{-1,-1},{0,0},{0,1},{0,2},{1,0},{1,1},{1,2},{2,0},{2,1},{2,2}};
int abs(int x)
{
return x>0?x:-x;
}
int sum;
int msb[10],msa[10];
int MergeSort(int s,int e)
{
int mid,cnt,t1,t2,i;
if (s >= e-1)
return 0;
mid=(s+e)>>1;
cnt=MergeSort(s,mid)+MergeSort(mid,e);
t1=s;
t2=mid;
i=s;
while (t1 < mid && t2 < e)
{
if (msa[t1] > msa[t2])
{
msb[i]=msa[t1];
t1++;
i++;
cnt+=t2-mid;
}
else
{
msb[i]=msa[t2];
t2++;
i++;
}
}
while (t1 < mid)
{
msb[i]=msa[t1];
i++;
t1++;
cnt+=t2-mid;
}
while (t2 < e)
{
msb[i]=msa[t2];
i++;
t2++;
}
for (i=s; i<e; i++)
msa[i]=msb[i];
return cnt;
}
void swap(int &a,int &b)
{
int t;
t=a;
a=b;
b=t;
}
class Board
{
public:
int a[3][3];
int x,y;
int h;
void readIn()
{
int i,j;
char str[2];
for (i=0; i<3; i++)
{
for (j=0; j<3; j++)
{
scanf("%s",str);
if (str[0] == 'x')
{
a[i][j]=0;
x=i;
y=j;
}
else
a[i][j]=str[0]-'0';
}
}
}
void printOut()
{
int i,j;
for (i=0; i<3; i++)
{
for (j=0; j<3; j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
printf("h=%d\n",getH());
}
bool checkLegal()
{
int b[10],i,j,k;
k=0;
for (i=0; i<3; i++)
{
for (j=0; j<3; j++)
{
msa[k]=a[i][j];
if (msa[k] != 0)
k++;
}
}
sum=MergeSort(0,8);
if (sum%2 == 1)
return false;
return true;
}
int getH()
{
int cnt,i,j;
cnt=0;
for (i=0; i<3; i++)
{
for (j=0; j<3; j++)
{
if (a[i][j] != 0)
cnt+=abs(i-tar[a[i][j]][0])+abs(j-tar[a[i][j]][1]);
}
}
h=cnt;
return cnt;
}
bool moveUp()
{
if (x == 0)
return false;
swap(a[x-1][y],a[x][y]);
x--;
return true;
}
bool moveDown()
{
if (x == 2)
return false;
swap(a[x+1][y],a[x][y]);
x++;
return true;
}
bool moveLeft()
{
if (y == 0)
return false;
swap(a[x][y-1],a[x][y]);
y--;
return true;
}
bool moveRight()
{
if (y == 2)
return false;
swap(a[x][y+1],a[x][y]);
y++;
return true;
}
};
int lim;
char ans[120];
bool IDDFS(int dep,Board b,char pr)
{
/*printf("%d %d\n",dep,lim);
b.printOut();
getchar();*/
Board tb;
b.getH();
if (b.h == 0)
return true;
if (dep > lim)
return false;
if (b.h+dep > lim)
return false;
tb=b;
if (pr != 'd' && (tb.moveUp() == true))
{
ans[dep]='u';
if (IDDFS(dep+1,tb,'u') == true)
return true;
}
tb=b;
if (pr != 'u' && (tb.moveDown() == true))
{
ans[dep]='d';
if (IDDFS(dep+1,tb,'d') == true)
return true;
}
tb=b;
if (pr != 'r' && (tb.moveLeft() == true))
{
ans[dep]='l';
if (IDDFS(dep+1,tb,'l') == true)
return true;
}
tb=b;
if (pr != 'l' && (tb.moveRight() == true))
{
ans[dep]='r';
if (IDDFS(dep+1,tb,'r') == true)
return true;
}
return false;
}
int main()
{
int prob;
Board b;
scanf("%d",&prob);
while (prob--)
{
b.readIn();
b.getH();
if (b.h == 0)
{
printf("\n");
if (prob > 0)
printf("\n");
continue;
}
if (b.checkLegal() == false)
{
printf("unsolvable\n");
if (prob > 0)
printf("\n");
continue;
}
for (lim=1; lim<100; lim++)
{
if (IDDFS(0,b,'w') == true)
break;
}
if (lim == 100)
{
printf("unsolvable\n");
if (prob > 0)
printf("\n");
}
else
{
ans[lim]='\0';
printf("%s\n",ans);
if (prob > 0)
printf("\n");
}
}
}