ICPC2012 Problem Cをやってみたよ。
http://www.cs.titech.ac.jp/icpc2012/icpc2012-mondai/icpc2012/contest/C_ja.html
サイコロを考えるのがややこしくて死にたくなった。
実行例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _T_ 0 /* 天:Top */
#define _B_ 1 /* 地:Bottom */
#define _E_ 2 /* 東:East */
#define _W_ 3 /* 西:West */
#define _S_ 4 /* 南:South */
#define _N_ 5 /* 北:North */
// サイコロの値の保持
typedef struct {
long x,y,z;
int topside;
int d[6];
} die_t;
// 1行入力
int input(int *n, int *tn, int *fn)
{
// 入力が 0 なら 0 を返す
// 入力が 1文字 なら 1 を返す
// 入力が 3文字 なら 2 を返す
char s[4];
char s2[4];
int x,y;
gets(s);
sscanf(s,"%d",&x);
sprintf(s2,"%d",x);
if(strlen(s2) == strlen(s))
{
if(0 == x)
{
return 0;
}
else
{
*n = x;
return 1;
}
}
y = s[2] - '0';
*tn = x;
*fn = y;
return 2;
}
// 指定座標にサイコロが存在するか確認する
int exist(long x, long y, long z, int n, die_t *dice)
{
int i;
for(i=0;i<n;i++)
{
if(
(dice[i].x == x) &&
(dice[i].y == y) &&
(dice[i].z == z))
{
return 1;
}
}
return 0;
}
int roll(die_t *dice, int i, int n)
{
int is_roll = 0;
int j,k,e,e2;
long x,y,z,stop;
int *d; // サイコロの目、d = {天,地,東,西,南,北} ※東西南北の北から見ている想定
int _e[6]; // サイコロの目の大きい順に方向をソート
int _x[] = {0,0,1,-1,0,0};
int _y[] = {0,0,0,0,1,-1};
x = dice[i].x;
y = dice[i].y;
z = dice[i].z;
d = dice[i].d;
stop = z; // Z=0では転がることができない!
// 転がす
while(stop){
// 方角ソート
for(j=0;j<6;j++)
{
for(k=0;k<6;k++)
{
if(d[k] == j+1)
{
_e[j] = k;
}
}
}
// 4~6の方向へ転がれるなら転がる。
for(j=5;j>2;j--)
{
e = _e[j]; // 面の方向(0天,1地,2東,3西,4南,5北)
if(e>1) // 3~6の面が天・地でない。
{
if(!exist(x+_x[e], y+_y[e], z-1, i, dice)) // 4~6の面がある方向にサイコロが無く、転がることができる場合。
{
// 転がる。座標処理
x += _x[e];
y += _y[e];
z--;
// 転がる。出目処理
e2 = (e%2==0)?e+1:e-1; // eの反対面
k = d[e];
d[e] = d[_T_];
d[_T_] = d[e2];
d[e2] = d[_B_];
d[_B_] = k;
// 転がり探し、止め。
j = 0;
// 回転フラグ
is_roll = 1;
}
}
}
stop = (0==j)? z:0; // 終了判定
}
dice[i].topside = d[_T_];
dice[i].x = x;
dice[i].y = y;
dice[i].z = z;
return is_roll;
}
// 上面と前面のサイコロの目から、サイコロのデータを登録する。
void setDice(die_t *die, int ti, int fi)
{
int wi;
int w[6][6]={ // 西方の目を天と北から得る。WEST = w[TOP][NORTH]
{0,3,5,2,4,0},
{4,0,1,6,0,3},
{2,6,0,0,1,5},
{5,1,0,0,6,2},
{3,0,6,1,0,4},
{0,6,2,5,3,0}
};
// サイコロの目の設定
wi = w[ti-1][fi-1];
die->d[_T_] = ti; die->d[_B_] = 7-ti;
die->d[_N_] = fi; die->d[_S_] = 7-fi;
die->d[_W_] = wi; die->d[_E_] = 7-wi;
}
// 主となる処理
char* main_proc(int n, int *t, int *f)
{
int i,j;
int ti; // 現在処理の対象としているサイコロにおけるtop,west,front(north)の目
long x,y,z; // 座標
int loop; // 繰り返しroll処理が必要か。
// サイコロのデータ。
die_t *dice;
// 最終結果の格納変数
char* s_res;
int result[6] = {0,0,0,0,0,0};
// サイコロのデータの領域割当。
dice = (die_t *)calloc(n ,sizeof(die_t));
// 落として転がす処理 //
for(i=0;i<n;i++)
{
setDice(&dice[i], t[i], f[i]);
// 落とす。
x = 0; y = 0; z = 0;
while(exist(x,y,z,i,dice)) z++;
dice[i].x = x;
dice[i].y = y;
dice[i].z = z;
dice[i].topside = t[i];
// 転がす。
loop = roll(dice, i, i);
while(loop)
{
loop = 0;
for(j=0;j<i+1;j++) loop = (roll(dice,j,i+1))?1:loop;
}
}
// 表示 //
for(i=0;i<n;i++)
{
x = dice[i].x;
y = dice[i].y;
z = dice[i].z;
ti = dice[i].topside;
if(!exist(x,y,z+1,n,dice)) result[ti-1]++;
}
// 文字列化
s_res = (char*)calloc(255,sizeof(char));
sprintf(s_res,"%d %d %d %d %d %d\n",result[0],result[1],result[2],result[3],result[4],result[5]);
s_res = (char*)realloc(s_res,sizeof(char)*(strlen(s_res)+1));
free(dice);
return s_res;
}
int main(void)
{
int i;
int n, *t, *f;
int nn, tn, fn;
int ret;
char *results;
char *rtmp;
int results_len;
results = (char*)calloc(1,sizeof(char));
// 入力
ret = input(&nn, &tn, &fn);
while(ret==1)
{
n = nn; // 入力されるサイコロの個数
// 入力データの領域割当
t = (int *)calloc(n ,sizeof(int));
f = (int *)calloc(n ,sizeof(int));
// サイコロデータ入力
for(i=0;i<n;i++)
{
if(2 != input(&nn, &tn, &fn)){
return 1;
}
t[i] = tn;
f[i] = fn;
}
// 主処理
rtmp = main_proc(n, t, f);
// 回答文字列連結
results_len = strlen(results);
results = (char*)realloc(results, sizeof(char)*(results_len+strlen(rtmp)+1));
strcpy(results+results_len, rtmp);
free(rtmp);
// 入力データ破棄
free(t);
free(f);
// 入力
ret = input(&nn, &tn, &fn);
}
//最終出力
printf("%s", results);
free(results);
return 0;
}
0件のコメント