i implemented A*. Its quite fast if i change the DEPTHLIM but the problem asks for not more than 50 moves. I either given WA or TLE. I get TLE when i increase the size of priority_queue other wise WA. Can someone give me testcases.
Code: Select all
#include<iostream>
#include<list>
#include<deque>
#include<queue>
#include<cassert>
#include<cstdio>
#include<vector>
#include<ext/hash_map>
#include<ext/hash_set>
#include<map>
#include<cmath>
#include<set>
#include<string>
#include<algorithm>
using namespace std;
using namespace __gnu_cxx;
typedef unsigned long long ull;
typedef long long ll;
/* BOARD SIZE */
#define MAX (4)
#define DEPTHLIM 50
#define HASHSIZE 1000000
#define CON (2)
#define CON2 (1)
#define MAX2 (16)
#define MAXI (15)
#define DELIM (0)
set <ull > ss1;
void swap(int &a,int &b)
{
int tmp;
tmp=a;
a=b;
b=tmp;
return;
}
int isvalid (int x, int y)
{
if ((x >= MAX) || (x < 0) || (y >= MAX) || (y < 0))
return 0;
return 1;
}
/* ENCODE the board in a 64 bit number with 4 bits for each state */
#define BASE 16
/* DIRECTION VECTORS */
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
char dir[4]={'R','D','L','U'};
int mx[MAX2]={3,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3};
int my[MAX2]={3,0,1,2,3,0,1,2,3,0,1,2,3,0,1,2};
#define N (1ULL)
/* COEFFS */
long long powerindex[MAX2]={N,N<<4,N<<8,N<<12,N<<16,N<<20,N<<24,N<<28,N<<32,N<<36,N<<40,N<<44,N<<48,N<<52,N<<56,N<<60};
inline int get(const int idx,const ull val) { return (val/powerindex[idx])%BASE; }
inline ull myset(const int idx,const ull val,const ull x){ return val + x*powerindex[idx]; }
/* CALCULATE MANHATTAN DISTANCE OF c */
int calc(int x,int y,int c){
return abs(x-mx[c]) + abs(y-my[c]);
}
/* CALCULATE MANHATTAN DISTANCE OF c if it is moved from (x1,y1)->(x2,y2) */
int h(int x1,int y1,int x2,int y2,int c){
return calc(x2,y2,c) - calc(x1,y1,c) ;
}
/* LINEAR index of the board if this were put in a single array */
#define LIN(x,y) (MAXI-((x*MAX) + y))
/* Given a board encoded as unsigned long long calculate the manhattan distance from target board */
int mhd(ull num){
int i,j,ts=0,x;
for(i=MAX-1;i>-1;i--)
for(j=MAX-1;j>-1;j--) {
x=num%BASE;
ts+=h(i,j,mx[x],my[x],x);
num/=BASE;
}
return ts;
}
/* Change hole from x1,y1 to x2,y2 and calculate the new value */
int chim(int x1,int y1,int x2,int y2,ull v,ull &newval){
int v1=get(LIN(x1,y1),v);
int v2=get(LIN(x2,y2),v);
newval=v;
newval=myset(LIN(x1,y1),newval,v2-v1);
newval=myset(LIN(x2,y2),newval,v1-v2);
return h(x2,y2,x1,y1,v2) + h(x1,y1,x2,y2,v1);
}
/* Store the backtrack indexes and the values, Better than a string in each level */
int bt[5000000];
int ct[5000000];
/*
* Structure of a board
* x,y is where the hole (DELIM or 0) is
* cost is the manhattan cost
* val is the encoded value of board ,so target value is 0x123456789ABCDEF
* lvl is the depth of the board , idx is the index for backtracking
* tcost is COEFF1*cost + lvl
*
*
*/
struct board{
int x,y;
int cost;
ull val;
int lvl,idx;
double tcost;
};
/* Is the position good , if yes then store the newval of the board and the
* total cost
*/
int isgood(int x1,int y1,int x2,int y2,ull val,ull &newval,int& tc){
if(!isvalid(x2,y2)) return 0;
tc=chim(x1,y1,x2,y2,val,newval);
if(ss1.find(newval)!=ss1.end()) return 0;
ss1.insert(newval);
return 1;
}
#define MYEPS 1e-6
bool operator<(const board &a,const board &b){
return (a.tcost > b.tcost && fabs(a.tcost-b.tcost)>MYEPS);
}
#define TARGET 0x123456789ABCDEF0ULL
/* The coeffs for the heuristic */
#define COEFF1 4
#define COEFF2 1
/* Print the solution */
void backfind(int ve){
if(ve==1) return;
backfind(bt[ve]);
printf("%c",ct[ve]);
}
/* Astar is bfs with priority queue */
int astar(ull num,int hx,int hy){
board tmp,tmp1;
int x,y,nx,ny,last=1;
ull val;
/* Priority queue orderd by least total cost at the top */
priority_queue<board> pq;
/* Initialize the board */
x=tmp.x=hx;
y=tmp.y=hy;
tmp.idx=last++;
bt[tmp.idx]=0;
ct[tmp.idx]=0;
tmp.lvl=1;
tmp.val=num;
tmp.cost=tmp.tcost=mhd(num);
tmp.tcost=COEFF1*tmp.cost + COEFF2*tmp.lvl;
isgood(x,y,x,y,tmp.val,val,y);
/* Push the board */
pq.push(tmp);
int notimes=0;
if(tmp.val==TARGET){
goto fail;
}
while(pq.size()){
tmp1=tmp=pq.top();
if(pq.size()>notimes) notimes=pq.size();
/* If the queue size is too big break, we are going to run out of memory */
if(notimes>HASHSIZE) break;
pq.pop();
x=tmp.x; y=tmp.y;
val=tmp.val;
/* There is no point using boards at greater depth than DEPTHLIM */
if(tmp.lvl > DEPTHLIM) continue;
/* Push the valid boards into the queue */
for(int i=0;i<4;i++){
nx=x+dx[i];
ny=y+dy[i];
if(isgood(x,y,nx,ny,val,tmp1.val,tmp1.cost)){
tmp1.x=nx;
tmp1.y=ny;
tmp1.lvl=tmp.lvl + 1;
tmp1.idx=last++;
tmp1.cost=tmp1.cost+tmp.cost;
tmp1.tcost=COEFF1*tmp1.cost + COEFF2*tmp1.lvl;
bt[last-1]=tmp.idx;
ct[last-1]=dir[i];
if(tmp1.val==TARGET){
backfind(last-1);
goto fail;
}
if(tmp1.lvl>DEPTHLIM) continue;
pq.push(tmp1);
}
}
}
fail:
//cout <<notimes<<endl;
if(notimes>HASHSIZE) return 0;
return 1;
}
/* Just a structure to see if the board is solvable
* otherwise it is not used. It
* just checks for feasibility of the board
*/
struct cell
{
int arr[MAX][MAX], u, v, lvl;
int cc;
ull hash;
};
cell target;
int parityh(int x,int y){
if(x&1) return 1;
return 0;
}
int paritya(int arr[MAX][MAX]){
int i,j,x,y,p,q;
int lc=0;
for(i=0;i<(MAX)*(MAX);i++){
x=i/MAX;
y=i%MAX;
if(arr[x][y]==(DELIM)) continue;
for(j=i+1;j<MAX*MAX;j++){
p=j/MAX;
q=j%MAX;
if(arr[p][q]==(DELIM)) continue;
if(arr[x][y]> arr[p][q]) lc++;
}
}
return lc &1;
}
int
main ()
{
int i, j;
for (i = 0; i < MAX; i++)
for (j = 0; j < MAX; j++)
target.arr[i][j] = (i) * MAX + j + 1;
target.u = target.v = MAX - 1;
target.arr[target.u][target.v] = DELIM;
int no=1;
cin >> no;
while (no--)
{
cell c;
ull num=0;
/* Encode the input value into a number */
for (i = 0; i < MAX; i++)
for (j = 0; j < MAX; j++)
{
int z = -1;
scanf (" %d", &z);
if (z == 0)
{
c.u = i;
c.v = j;
c.arr[i][j] = DELIM;
z=DELIM;
}
else
c.arr[i][j] = z;
num=num*BASE + z;
}
/* Parity is even the board is not solvable */
int k=paritya(c.arr) + parityh(c.u,c.v);
if((k&1)==0){ cout <<"This puzzle is not solvable."<<endl; continue; }
ss1.clear();
if(!astar(num,c.u,c.v)){
;
}
cout <<endl;
}
}