USACO SECTION 1.4 The Clocks

本文探讨了如何使用九种不同的移动方式,将三个3x3的钟盘上的指针从任意位置调整到12点钟位置。通过算法实现最小序列的移动方案,确保所有指针同时指向正确方向。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

The Clocks
IOI'94 - Day 2
Consider nine clocks arranged in a 3x3 array thusly:
|-------|    |-------|    |-------|    
|       |    |       |    |   |   |    
|---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.

MoveAffected clocks
1ABDE
2ABC
3BCEF
4ADG
5BDEFH
6CFI
7DEGH
8GHI
9EFHI


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]);	
}


 

这个方法对我这个菜鸟来说感觉很有应用价值啊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值