IOI'94 - Day 2
|-------| |-------| |-------| | | | | | | | |---O | |---O | | O | | | | | | | |-------| |-------| |-------| A B C |-------| |-------| |-------| | | | | | | | O | | O | | O | | | | | | | | | | |-------| |-------| |-------| D E F |-------| |-------| |-------| | | | | | | | O | | O---| | O | | | | | | | | | |-------| |-------| |-------| G H I
The goal is to find a minimal sequence of moves to return all the dials to 12 o'clock. Nine different ways to turn the dials on the clocks are supplied via a table below; each way is called a move. Select for each move a number 1 through 9 which will cause the dials of the affected clocks (see next table) to be turned 90 degrees clockwise.
Move | Affected clocks |
1 | ABDE |
2 | ABC |
3 | BCEF |
4 | ADG |
5 | BDEFH |
6 | CFI |
7 | DEGH |
8 | GHI |
9 | EFHI |
Example
Each number represents a time accoring to following table:9 9 12 9 12 12 9 12 12 12 12 12 12 12 12 6 6 6 5 -> 9 9 9 8-> 9 9 9 4 -> 12 9 9 9-> 12 12 12 6 3 6 6 6 6 9 9 9 12 9 9 12 12 12
[But this might or might not be the `correct' answer; see below.]
PROGRAM NAME: clocks
INPUT FORMAT
Lines 1-3: | Three lines of three space-separated numbers; each number represents the start time of one clock, 3, 6, 9, or 12. The ordering of the numbers corresponds to the first example above. |
SAMPLE INPUT (file clocks.in)
9 9 12 6 6 6 6 3 6
OUTPUT FORMAT
A single line that contains a space separated list of the shortest sequence of moves (designated by numbers) which returns all the clocks to 12:00. If there is more than one solution, print the one which gives the lowest number when the moves are concatenated (e.g., 5 2 4 6 < 9 3 1 1).
SAMPLE OUTPUT (file clocks.out)
4 5 8 9
/*
ID: conicoc1
LANG: C
TASK: clocks
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define A 0
#define B 1
#define C 2
#define D 3
#define E 4
#define F 5
#define G 6
#define H 7
#define I 8
void Move1(int *Clocks)
{
Clocks[A]+=3;
Clocks[B]+=3;
Clocks[D]+=3;
Clocks[E]+=3;
}
void Move2(int *Clocks)
{
Clocks[A]+=3;
Clocks[B]+=3;
Clocks[C]+=3;
}
void Move3(int *Clocks)
{
Clocks[B]+=3;
Clocks[C]+=3;
Clocks[E]+=3;
Clocks[F]+=3;
}
void Move4(int *Clocks)
{
Clocks[A]+=3;
Clocks[D]+=3;
Clocks[G]+=3;
}
void Move5(int *Clocks)
{
Clocks[B]+=3;
Clocks[D]+=3;
Clocks[E]+=3;
Clocks[F]+=3;
Clocks[H]+=3;
}
void Move6(int *Clocks)
{
Clocks[C]+=3;
Clocks[F]+=3;
Clocks[I]+=3;
}
void Move7(int *Clocks)
{
Clocks[D]+=3;
Clocks[E]+=3;
Clocks[G]+=3;
Clocks[H]+=3;
}
void Move8(int *Clocks)
{
Clocks[G]+=3;
Clocks[H]+=3;
Clocks[I]+=3;
}
void Move9(int *Clocks)
{
Clocks[E]+=3;
Clocks[F]+=3;
Clocks[H]+=3;
Clocks[I]+=3;
}
int IsFinished(int *Clocks)
{
int i;
for(i=0;i<9;i++)
if(Clocks[i]%12!=0)
return 0;
return 1;
}
void swap(int *a,int *b)
{
int i;
for(i=0;i<9;i++)
a[i]=b[i];
}
int main()
{
FILE *fin,*fout;
fin=fopen("clocks.in","r");
fout=fopen("clocks.out","w");
int Clocks[9],temp[9];
int M[9],P[9]={0},Sum=28; //记录每种移动方式的次数
int i,j,k,t;
for(i=0;i<9;i++)
{
fscanf(fin,"%d",&Clocks[i]);
}
swap(temp,Clocks);
for(M[0]=0;M[0]<=3;M[0]++)
{
for(M[1]=0;M[1]<=3;M[1]++)
{
for(M[2]=0;M[2]<=3;M[2]++)
{
for(M[3]=0;M[3]<=3;M[3]++)
{
for(M[4]=0;M[4]<=3;M[4]++)
{
for(M[5]=0;M[5]<=3;M[5]++)
{
for(M[6]=0;M[6]<=3;M[6]++)
{
for(M[7]=0;M[7]<=3;M[7]++)
{
for(M[8]=0;M[8]<=3;M[8]++)
{
for(i=0;i<9;i++)
{
for(j=0;j<M[i];j++)
switch(i)
{
case 0:Move1(Clocks);break;
case 1:Move2(Clocks);break;
case 2:Move3(Clocks);break;
case 3:Move4(Clocks);break;
case 4:Move5(Clocks);break;
case 5:Move6(Clocks);break;
case 6:Move7(Clocks);break;
case 7:Move8(Clocks);break;
case 8:Move9(Clocks);break;
}
}
if(IsFinished(Clocks))
{
if(Sum>M[0]+M[1]+M[2]+M[3]+M[4]+M[5]+M[6]+M[7]+M[8])
{
for(k=0;k<9;k++)
{
P[k]=M[k];
}
Sum=M[0]+M[1]+M[2]+M[3]+M[4]+M[5]+M[6]+M[7]+M[8];
}
// getchar();
}
swap(Clocks,temp);
}
}
}
}
}
}
}
}
}
k=0;
t=0;
for(i=0;i<9;i++)
{
for(j=0;j<P[i];j++)
{
k++;
}
}
for(i=0;i<9;i++)
{
for(j=0;j<P[i];j++)
{
fprintf(fout,"%d",i+1);
t++;
if(t!=k)
fprintf(fout," ");
}
}
fprintf(fout,"\n");
return 0;
}
虐啊。。太虐了。。做到1.4就开始虐了。。。
让我回想一下我开始的各种想法。。
一开始以为选择移动的9种方式是有优先权的。。。不停的再想优先权,想了半天不对。
后来模拟了一下已知的过程,对于给定的9个钟,方法的顺序可以不一样,所以就有了那个坑爹的解九元一次方程组,还专门复习了一下矩阵的高斯消元,
折腾了半天发现等式右边是4n-1或2或3,是不定的,思考无果。放弃
最后实在没办法了,就只好用暴力了
对于每种方法最多只能执行3次,因为4次就等于没有动,所以开辟了一个数组存放每种方法的执行次数。
本打算一旦找到符合的,就弹出循环,后来样例3检测的时候出错了,发现需要比较所有可能的情况,选数组和最低的情况。
另外最后所要求的输出方法,每个数字之间有空格,最后和开头没有空格,对于整体输出想了半天没有什么好的方法,结果码了一大串。。。
去NOCOW上面研究一下BFS和DFS的方法。对于深搜和广搜的理解还是不够深刻啊啊。
/*
ID: conicoc1
LANG: C
TASK: barn1
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int Stack[3000000];
int Queue[3000000];
int Flag[3000000];
int road[3000000][2];
int top=0,front=0,rear=0;
int clock[9];
int temp[9];
void act(int p)
{
int i,j,k;
if(p==1)
{
clock[0]=(clock[0]+1)%4;
clock[1]=(clock[1]+1)%4;
clock[3]=(clock[3]+1)%4;
clock[4]=(clock[4]+1)%4;
}
if(p==2)
{
clock[0]=(clock[0]+1)%4;
clock[1]=(clock[1]+1)%4;
clock[2]=(clock[2]+1)%4;
}
if(p==3)
{
clock[2]=(clock[2]+1)%4;
clock[1]=(clock[1]+1)%4;
clock[5]=(clock[5]+1)%4;
clock[4]=(clock[4]+1)%4;
}
if(p==4)
{
clock[0]=(clock[0]+1)%4;
clock[3]=(clock[3]+1)%4;
clock[6]=(clock[6]+1)%4;
}
if(p==5)
{
clock[5]=(clock[5]+1)%4;
clock[1]=(clock[1]+1)%4;
clock[3]=(clock[3]+1)%4;
clock[4]=(clock[4]+1)%4;
clock[7]=(clock[7]+1)%4;
}
if(p==6)
{
clock[2]=(clock[2]+1)%4;
clock[5]=(clock[5]+1)%4;
clock[8]=(clock[8]+1)%4;
}
if(p==7)
{
clock[6]=(clock[6]+1)%4;
clock[7]=(clock[7]+1)%4;
clock[3]=(clock[3]+1)%4;
clock[4]=(clock[4]+1)%4;
}
if(p==8)
{
clock[6]=(clock[6]+1)%4;
clock[7]=(clock[7]+1)%4;
clock[8]=(clock[8]+1)%4;
}
if(p==9)
{
clock[8]=(clock[8]+1)%4;
clock[7]=(clock[7]+1)%4;
clock[5]=(clock[5]+1)%4;
clock[4]=(clock[4]+1)%4;
}
}
int invert()
{
int i,sum=0;
int n=1;
for(i=0;i<9;i++)
{
sum+=clock[i]*n;
n*=4;
}
return sum;
}
void revert(int sum)
{
int i;
for(i=0;i<9;i++)
{
clock[i]=sum%4;
sum/=4;
}
}
void InStack(int s)
{
if(s==Queue[0])
{
return;
}
// printf("%d %d\n",s,road[s][0]);
InStack(road[s][0]);
Stack[top++]=road[s][1]; //最下面是根
}
int main()
{
FILE *fin,*fout,*ftxt;
fin=fopen("clocks.in","r");
fout=fopen("clocks.out","w");
memset(Flag,-1,sizeof(Flag));
memset(road,-1,sizeof(road));
int i,j,k;
for(i=0;i<9;i++)
{
fscanf(fin,"%d",&clock[i]);
clock[i]=(clock[i]/3)%4;
}
int s,t; //保存转换的状态
s=invert();
Queue[rear++]=s; //将该状态进队
printf("rear:%d,s:%d,Queue[0]:%d",rear,s,Queue[0]);
Flag[s]=1;
while(front!=rear)
{
s=Queue[front++];
revert(s);
for(j=0;j<9;j++)
temp[j]=clock[j];
for(i=1;i<=9;i++)
{
act(i);
t=invert();
// printf("%d\n",t);
if(t==0)
getchar();
if(Flag[t]==-1)
{
Flag[t]=1;
Queue[rear++]=t;
road[t][0]=s;
road[t][1]=i;
}
for(j=0;j<9;j++)
clock[j]=temp[j];
}
if(Flag[0]==1)
break;
}
// for(j=0;j<9;j++)
// printf("%d",clock[j]);
//接下来将路径递归进栈
InStack(0);
for(i=0;i<top;i++)
printf("%d ",Stack[i]);
}
这个方法对我这个菜鸟来说感觉很有应用价值啊