SuperCon2011予選

PriorityQueueを使って全ての地点までのk最短路を求めた後にメモ化再帰
ソースコードの後半は指定されていたテンプレート+入力データのコピーだけ。

/* SuperCon 2011 予選問題C用テンプレート
   ・解答プログラムはこのテンプレートに従って作成すること.
  ・解答プログラムは1つのファイルで,チーム名.c という名前にすること.
  ・入力の方式は,あらかじめ入力ファイル(例:input_sample.txt)を作っ
   ておき,実行時にファイル名を指定する方式です.
*/

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* ↓以下の範囲は変更可能 */

#include <limits.h>

#define HEAPTABLESIZE 4*210*210*210

int heapData[HEAPTABLESIZE];
int heapTable[HEAPTABLESIZE][3];
int heapSize=0;
int heapTableSize=HEAPTABLESIZE;
int heapTableCur=0;

void heapPop(int*,int*,int*);
void heapPush(int,int,int);
int heapEmpty();

void heapDown(int);
void heapUp(int);

int rec(int x,int y,int o);
void solve(int _h,int _w,int _k,int *ans_len,int *ans_num);

int k,w,h;
int mv[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int dist[210][210][210];
int filled[210][210];
int MAP[200+1][200+1][4];
int cache[210][210][210];

int heapEmpty()
{
	return (heapSize==0);
}

void heapPop(int *c,int *x,int *y)
{
	if(heapSize==0)
	{
		*c=-1,*x=-1,*y=-1;
	}
	else if(heapSize==1)
	{
		int r=heapData[1];
		heapData[heapSize]=-1;
		heapSize=0;
		*c=heapTable[r][0],*x=heapTable[r][1],*y=heapTable[r][2];
	}
	else
	{
		int r=heapData[1];
		heapData[1]=heapData[heapSize];
		heapSize--;
		heapDown(1);
		*c=heapTable[r][0],*x=heapTable[r][1],*y=heapTable[r][2];
	}
}

void heapPush(int c,int x,int y)
{
	heapTableCur=(heapTableCur+1)%heapTableSize;
	heapTable[heapTableCur][0]=c;
	heapTable[heapTableCur][1]=x;
	heapTable[heapTableCur][2]=y;

	heapSize++;
	heapData[heapSize]=heapTableCur;

	heapUp(heapSize);
}

void heapUp(int k)
{
	int p=k/2;
	if(k==1)
		;
	else if(heapTable[heapData[k]][0]<heapTable[heapData[p]][0])
	{
		int t=heapData[k];
		heapData[k]=heapData[p];
		heapData[p]=t;
		heapUp(p);
	}
	else
		;
}

void heapDown(int k)
{
	int n1=2*k,n2=2*k+1;
	if(heapSize<n1)
	{
		;
	}
	else if(heapSize<n2)
	{
		if(heapTable[heapData[n1]][0]<heapTable[heapData[k]][0])
		{
			int t=heapData[k];
			heapData[k]=heapData[n1];
			heapData[n1]=t;
			heapDown(n1);
		}
		else
		{
			;
		}
	}
	else
	{
		if(heapTable[heapData[n1]][0]<heapTable[heapData[n2]][0] && 
				heapTable[heapData[n1]][0]<heapTable[heapData[k]][0])
		{
			int t=heapData[k];
			heapData[k]=heapData[n1];
			heapData[n1]=t;
			heapDown(n1);
		}
		else if(heapTable[heapData[n2]][0]<=heapTable[heapData[n1]][0] && 
				heapTable[heapData[n2]][0]<heapTable[heapData[k]][0])
		{
			int t=heapData[k];
			heapData[k]=heapData[n2];
			heapData[n2]=t;
			heapDown(n2);
		}
		else
		{
			;
		}
	}	
}

int rec(int x,int y,int o)
{
	int pp;

	int *r=&cache[x][y][o];
	if(*r!=-1)
		;
	else if(x==0 && y==0 && o==0)
		*r=1;
	else
	{
		*r=0;
		for(pp=0;pp<4;pp++)
			if(MAP[x][y][pp]!=0)
			{
				int xx=x+mv[pp][0],yy=y+mv[pp][1];
				int cc=dist[x][y][o]-MAP[x][y][pp];
				int bo=0,ce=k-1;
				while(1<ce-bo)
				{
					int me=(bo+ce)/2;
					if(dist[xx][yy][me]<cc)
						bo=me;
					else
						ce=me;
				}
				if(dist[xx][yy][bo]==cc)
					*r+=rec(xx,yy,bo);
				else if(dist[xx][yy][ce]==cc)
					*r+=rec(xx,yy,ce);
				else
					;
			}
	}
	return *r;
}

void solve(int _h,int _w,int _k,int *ans_len,int *ans_num)
{
	int pp,qq,rr;
	int c,x,y;
	int cc,xx,yy;

	k=_k,w=_w,h=_h;
	h++,w++;

	for(pp=0;pp<210;pp++)
		for(qq=0;qq<210;qq++)
		{
			for(rr=0;rr<210;rr++)
				dist[pp][qq][rr]=INT_MAX;
			filled[pp][qq]=0;
		}

	heapPush(0,0,0);

	while(!heapEmpty())
	{
		heapPop(&c,&x,&y);

		if(filled[x][y]==k ||
			 	(0<filled[x][y] && dist[x][y][filled[x][y]-1]==c))
		{
			;
		}
		else
		{
			dist[x][y][filled[x][y]]=c;
			filled[x][y]++;

			//if(x!=w-1 || y!=h-1)
				for(pp=0;pp<4;pp++)
					if(MAP[x][y][pp]!=0)
					{
						cc=c+MAP[x][y][pp];
						xx=x+mv[pp][0];
						yy=y+mv[pp][1];

						//if(!(filled[xx][yy]==k || (0<filled[xx][yy] && dist[xx][yy][filled[xx][yy]-1]==cc)))
						//{
							heapPush(cc,xx,yy);
						//}
					}
		}
	}

	memset(cache,-1,sizeof(cache));
	if(dist[w-1][h-1][k-1]!=INT_MAX)
	{
		*ans_len=dist[w-1][h-1][k-1];
		*ans_num=rec(w-1,h-1,k-1);
	}
	else
	{
		*ans_len=0;
		*ans_num=0;
	}
}

/* ↑上記の範囲は変更可能 */

int main(int argc, char** argv) {
  int answer_length = -1; /* この変数に k 番目に長い経路の長さを代入してください */
  int answer_number = -1; /* この変数に k 番目に長い経路の総数を代入してください */
  int m, n, k;
  int D[200+1][200+1][4];
  char* problem_file;
  clock_t start, end;
  FILE* fp;

  int i, x, y;
  char buf[0xffff];
  char* p;

  if (argc <= 1) {
    fprintf(stderr, "Enter the input file.\n");
    exit(EXIT_FAILURE);
  }

  problem_file = argv[1];
  fp = fopen(problem_file, "r");
  if (fp == NULL) {
    fprintf(stderr, "Cannot open %s.\n", problem_file);
    exit(EXIT_FAILURE);
  }

  p = fgets(buf, 0xffff, fp);
  assert(p != 0);

  m = atoi(strtok(buf, ", \n"));
  n = atoi(strtok(NULL, ", \n"));
  k = atoi(strtok(NULL, ", \n"));
  assert(m > 0 && m <= 200);
  assert(n > 0 && n <= 200);
  assert(k > 0 && k <= 200);
  for (y = 0; y <= n; y++) {
    p = fgets(buf, 0xffff, fp);
    assert(p != 0);
    p = strtok(buf, ", \n");
    for (i = 0; i < m; i++) {
      int length = atoi(p);
      assert(length >= 0 && length <= 20);
      D[i][y][1] = length;
      D[i+1][y][3] = length;
      p = strtok(NULL, ", \n");
    }
    D[0][y][3] = 0;
    D[m][y][1] = 0;
  }
  for (x = 0; x <= m; x++) {
    p = fgets(buf, 0xffff, fp);
    assert(p != 0);
    p = strtok(buf, ", \n");
    for (i = 0; i < n; i++) {
      int length = atoi(p);
      assert(length >= 0 && length <= 20);
      D[x][i][0] = length;
      D[x][i+1][2] = length;
      p = strtok(NULL, ", \n");
    }
    D[x][0][2] = 0;
    D[x][n][0] = 0;
  }

  fclose(fp);

  /* 入力した情報を画面に出力する(デバッグ等に使って下さい)
   提出時は削除しないで,このようにコメントアウトすること
  printf("The input graph\n");
  for (i = 2*n; i >= 0; i--) {
    y = i / 2;
    if (i % 2 == 0) {
      printf("+");
      for (x = 0; x < m; x++) {
        assert(D[x][y][1] == D[x+1][y][3]);
        printf("%d+", D[x][y][1]);
      }
      assert(D[0][y][3] == 0);
      assert(D[m][y][1] == 0);
    } else if (i > 0) {
      for (x = 0; x <= m; x++) {
        assert(D[x][y][0] == D[x][y+1][2]);
        assert(y != n-1 || D[x][y+1][0] == 0);
        printf("%d ", D[x][y][0]);
      }
    } else {
      for (x = 0; x <= m; x++) {
        assert(D[x][y][2] == 0);
      }
    }
    printf("\n");
  }
  printf("\n");
  */

  /* 時間計測用(デバッグ等に使って下さい)
   提出時は削除しないで,このようにコメントアウトすること
  start = clock();
  */

/* ↓以下の範囲は変更可能 */
	int pp,qq,rr;
	for(pp=0;pp<201;pp++)
		for(qq=0;qq<201;qq++)
			for(rr=0;rr<4;rr++)
				MAP[pp][qq][rr]=D[pp][qq][rr];
	solve(n,m,k,&answer_length,&answer_number);

/* ↑上記の範囲は変更可能 */


  /* 時間計測用(デバッグ等に使って下さい)
   提出時は削除しないで,このようにコメントアウトすること
  end = clock();
  printf("%s, %f, %d, %d\n", problem_file, (double)(end - start) / CLOCKS_PER_SEC, answer_length, answer_number);
  */

  printf("%s, %d, %d\n", problem_file, answer_length, answer_number);
  return 0;
}