#include<stdio.h>
#include<stdlib.h>
#define ROW 4
#define COL 4
#define LIMIT 45
typedef struct {
  int row;
  int col;
}location;

void swap(int **,location,location);
int Search_min_path(int **,location,location,int,int);
int incorrect(int **);

int main(){
  int **puzzle;
  int i,j,limit,move_count=0,min;
  location pre,current;

  puzzle = malloc(sizeof(int*)*ROW);
  for(i=0;i<ROW;i++)puzzle[i] = malloc(sizeof(int)*COL);

  for(i=0;i<ROW;i++)for(j=0;j<COL;j++)scanf("%d",&puzzle[i][j]);

  pre.row=-1;
  pre.col=-1;
  for(i=0;i<ROW;i++)for(j=0;j<COL;j++)if(puzzle[i][j] == 0){
	current.row = i;
	current.col = j;
      }
  limit = incorrect(puzzle);
  //printf("%d\n",limit);
  for(;limit <= LIMIT;limit++){
    min = Search_min_path(puzzle,pre,current,limit,move_count);
    if(-1 != min){
      printf("%d\n",min);
      break;
    }
  }

  for(i=0;i<ROW;i++)free(puzzle[i]);
  free(puzzle);
  
  return 0;
}

int Search_min_path(int **puzzle,location pre,location current,int limit,int move_count){
  int **backup_puzzle;
  int i,j,h,state;
  location next;

  h = incorrect(puzzle);
  if(move_count + h >limit)return -1;
  if(0 == h){
    /**
    for(i=0;i<ROW;i++){
      for(j=0;j<COL;j++)printf(" %d",puzzle[i][j]);
      printf("\n");
    }
    printf("\n");
    **/
    return move_count;
  }

  backup_puzzle = malloc(sizeof(int*)*ROW);
  for(i=0;i<ROW;i++)backup_puzzle[i] = malloc(sizeof(int)*COL);

  for(i=0;i<ROW;i++)for(j=0;j<COL;j++)backup_puzzle[i][j] = puzzle[i][j];
  next = current;
  move_count++;

  /*********************** up ****************************/
  if(current.row -1 >= 0 && pre.row != current.row -1){
    next.row --;
    swap(puzzle,current,next);
    state = Search_min_path(puzzle,current,next,limit,move_count);
    if(-1 != state){
      /**
      for(i=0;i<ROW;i++){
	for(j=0;j<COL;j++)printf(" %d",backup_puzzle[i][j]);
	printf("\n");
      }
      printf("\n");
      **/
      for(i=0;i<ROW;i++)free(backup_puzzle[i]);
      free(backup_puzzle);
      return state;
    }
  }
  /*********************** up ****************************/

  for(i=0;i<ROW;i++)for(j=0;j<COL;j++)puzzle[i][j] = backup_puzzle[i][j];
  next= current;

  /*********************** down ****************************/
  if(current.row +1 < ROW && pre.row != current.row +1){
    next.row ++;
     swap(puzzle,current,next);
    state = Search_min_path(puzzle,current,next,limit,move_count);
    if(-1 != state){
      /**
      for(i=0;i<ROW;i++){
	for(j=0;j<COL;j++)printf(" %d",backup_puzzle[i][j]);
	printf("\n");
      }
      printf("\n");
      **/
      for(i=0;i<ROW;i++)free(backup_puzzle[i]);
      free(backup_puzzle);
      return state;
    }
  }
  /*********************** down ****************************/

  for(i=0;i<ROW;i++)for(j=0;j<COL;j++)puzzle[i][j] = backup_puzzle[i][j];
  next= current;

  /*********************** left ****************************/
  if(current.col -1 >=0 && pre.col != current.col -1){  
    next.col --;
    swap(puzzle,current,next);
    state = Search_min_path(puzzle,current,next,limit,move_count);
    if(-1 != state){
      /**
      for(i=0;i<ROW;i++){
	for(j=0;j<COL;j++)printf(" %d",backup_puzzle[i][j]);
	printf("\n");
      }
      printf("\n");
      **/
      for(i=0;i<ROW;i++)free(backup_puzzle[i]);
      free(backup_puzzle);
      return state;
    }
  }
  /*********************** left ****************************/

  for(i=0;i<ROW;i++)for(j=0;j<COL;j++)puzzle[i][j] = backup_puzzle[i][j];
  next= current;

  /*********************** right ****************************/
  if(current.col +1 <COL && pre.col != current.col +1){
    next.col ++;
    swap(puzzle,current,next);
    state = Search_min_path(puzzle,current,next,limit,move_count);
    if(-1 != state){
      /**
      for(i=0;i<ROW;i++){
	for(j=0;j<COL;j++)printf(" %d",backup_puzzle[i][j]);
	printf("\n");
      }
      printf("\n");
      **/
      for(i=0;i<ROW;i++)free(backup_puzzle[i]);
      free(backup_puzzle);
      return state;
    }
  }
  /*********************** right ****************************/

  for(i=0;i<ROW;i++)for(j=0;j<COL;j++)puzzle[i][j] = backup_puzzle[i][j];
  
  
  for(i=0;i<ROW;i++)free(backup_puzzle[i]);
  free(backup_puzzle);
  return -1;
}

int incorrect(int **puzzle){
  int i,j,num = 1,h=0,flag=0,tate,yoko,n,m;
  for(num =1;num<ROW*COL;num++){
    n = (num-1)/ROW;
    m = (num-1)%COL;
    for(i=0;i<ROW;i++){
      for(j=0;j<COL;j++){
	if(puzzle[i][j] == num%(ROW*COL)){
	  tate = i-n;
	  if(tate < 0)tate *=-1;
	  yoko = j-m;
	  if(yoko < 0)yoko *=-1;
	  flag = 1;
	  break;
	}
      }
      if(flag==1)break;
    }
    flag = 0;
    h += tate + yoko;
  }
  return h;
}

void swap(int **puzzle,location A,location B){
  int num;
  num = puzzle[A.row][A.col];
  puzzle[A.row][A.col] = puzzle[B.row][B.col];
  puzzle[B.row][B.col]=num;
}
  

  
    

  



Measured memory_bytes: 2148