算法日记(Java实现)第20170308(7)期——POJ1222

POJ1222 EXTENDED LIGHTS OUT(枚举方法)

题目地址:http://poj.org/problem?id=1222



最近写了许多的算法题,里面也有一些很有意思的题,但没有更新博客,今天起打算更新前一阶段学习算法的成果。

和以往不同的是,以后的代码思路都体现在详尽的注释里。

import java.util.Scanner;

public class Main{

	/*解题思路
	 * 
	 * 1.时钟的状态只有四种(分别对应0.1.2.3),那么顺时针旋转90°
	 * 就是clock_time = (clock_time+1)%4,九个时钟就用一个
	 * 数组表示它们的状态。
	 * 2.同时每一种操作都有周期性限制,也即最多需要几次操作,多于这个
	 * 次数产生循环。本题中,操作的最多次数为3,如果操作四次,则和没有
	 * 操作是一样的..故用一个数组表示九个操作每个操作需要进行的次数。
	 * 3.对移动方法进行枚举,枚举方法123,共64种情况,则A的状态只
	 * 能通过操作4来改变,所以要A达到十二点,那么操作4的次数是一定的了。
	 * 同理,改变B只能操作5,改变C只能操作6。那么操作123456的次数确定。
	 * 4.这时候,同理改编D只能操作7,改编F只能操作9,所以12345679确定。
	 * 5.这时候还剩EGHI还没确定,操作8还没确定。由于操作8只能同时改编GHI,
	 * 不改变E,那么看看E是否已经到达十二点,看看GHI是否相同。
	 * 
	 */
	static private int[] clock_time;	//时钟初始状态
	static private int[] enumeration;	//用于枚举123操作,初始000
	static private int min_time = 28;		//记录当前最少序列
	static private int[] min_seq;
	//9种操作
	static private int [][] op = new int[][]{
		//A B C D E F G H I
		{1,1,0,1,1,0,0,0,0},	//op1:ABDE
		{1,1,1,0,0,0,0,0,0},	//op2:ABC
		{0,1,1,0,1,1,0,0,0},	//op3:BCEF
		{1,0,0,1,0,0,1,0,0},	//op4:ADG
		{0,1,0,1,1,1,0,1,0},	//op5:BDEFH
		{0,0,1,0,0,1,0,0,1},	//op6:CFI
		{0,0,0,1,1,0,1,1,0},    //op7:DEGH
        {0,0,0,0,0,0,1,1,1},    //op8:GHI
        {0,0,0,0,1,1,0,1,1}		//op9:EFHI
	};
	
	static private void input(){
		Scanner sc = new Scanner(System.in);
		clock_time = new int[9];
		for(int i = 0; i < 9; i++){
			clock_time[i] = sc.nextInt();
		}
	}
	//枚举操作123的不同次数,每次枚举都+1
	static private void enumerate(){
		enumeration[0]++;
		if(enumeration[0] == 4){
			enumeration[1]++;
			enumeration[0] = 0;
		}
		if(enumeration[1] == 4){
			enumeration[2]++;
			enumeration[1] = 0;
		}
	}
	
	//由一种枚举状态,确定此状态能否达成要求,若达到要求,返回总的操作次数,达不到要求,返回28次
	//1.确定123的操作次数(已经得到)
	//2.施加123操作给所有时钟,得到ABC的状态,从而确定456的操作次数
	//3.施加456操作给所有时钟,得到DF的状态,从而确定79的操作次数
	//4.施加79操作给所有时钟,得到EGHI的状态
	//5.判断GHI是否相同,E是否达到12点,若其一条件不满足,则返回28次
	//6.如果满足,确定8操作的次数。输出所有操作,根据次数确定该操作重复输出的次数
	public static void guess(int []enumeration){
//		System.out.println("本次枚举:");
//		for(int i = 0; i < 3; i++){
//			System.out.print(enumeration[i] + " ");
//		}
//		System.out.println();
			
			
		//临时记录状态的时钟
		int [] t = new int[9];
		for(int i = 0; i<9;i++){
			t[i] = clock_time[i];
		}
		//每种操作执行的次数
		int [] opn = new int[9];
		opn[0] = enumeration[0];
		opn[1] = enumeration[1];
		opn[2] = enumeration[2];
		//施加123操作给所有时钟
		for(int i = 0; i < 3; i++){
			for(int j = 0; j < 9; j++){
				t[j] = (t[j] + opn[i] * op[i][j])%4;
			}
		}
		
//		System.out.println("施加操作123后:");
//		for(int j = 0; j < 9; j++){
//			System.out.print(t[j] + " ");
//		}
//		System.out.println();
		
		//通过ABC的状态,得到456的操作次数
		opn[3] = (4 - t[0]) % 4;
		opn[4] = (4 - t[1]) % 4;
		opn[5] = (4 - t[2]) % 4;
		
		//施加456操作给所有时钟
		for(int i = 3; i < 6; i++){
			for(int j = 0; j < 9; j++){
				t[j] = (t[j] + opn[i] * op[i][j])%4;
			}
		}
		
//		System.out.println("施加操作456后:");
//		for(int j = 0; j < 9; j++){
//			System.out.print(t[j] + " ");
//		}
//		System.out.println();
		
		//通过DF,确定79的操作次数
		opn[6] = (4 - t[3]) % 4;
		opn[8] = (4 - t[5]) % 4;
		
		//施加79操作给所有时钟
		for(int i = 6; i <= 8; i++){
			if(i == 7)
				continue;
			for(int j = 0; j < 9; j++){
				t[j] = (t[j] + opn[i] * op[i][j])%4;
			}
		}
				
//		System.out.println("施加操作79后:");
//		for(int j = 0; j < 9; j++){
//			System.out.print(t[j] + " ");
//		}
//		System.out.println();
		
		//判断
		if(t[4] != 0 || t[6] != t[7] || t[7] != t[8])
		{
//			System.out.println("本次不满足条件");
			return;
		}
		//计算操作8
		opn[7] = (4 - t[6]) % 4;
//		System.out.println("本次操作序列:");
		int sum = 0;
		for(int i = 0; i < 9; i++){
			sum += opn[i];
		}
		if(sum < min_time){
			min_seq = opn;
		}
		else
			return;
	}
	
	public static void main(String[] args) {
		input();
		enumeration = new int[3];	//自动初始化000
		for(int i = 0; i < 64;i++){
			guess(enumeration);
			enumerate();
		}
		for(int i = 0; i < 9; i++){
			for(int j = 0; j < min_seq[i]; j++){
				System.out.print(i + 1 + " ");
			}
		}
	}

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值