hdu 2234 IDA*算法

Problem Description

一天机器人小A在玩一个简单的智力游戏,这个游戏是这样的,在一个4*4的矩阵中分别有4个1,4个2,4个3和4个4分别表示4种不同的东西,每一步小A可以把同一行的4个数往左移或者往右移一步或者把同一列的4个数字往上移或者往下移一步(1,2,3,4往左移后是2,3,4,1),小A现在想知道进过最少的几步移动可以将矩阵的每行上的4个数字都一样或者每列上的4个数字都一样。但是小A又不想走太多步,他只要知道最少步数是否少于等于5步,是的话输出准确的步数,否则输出-1。
 

Input
先输入一个整数T,表示有T组数据。
对于每组数据输入4行,每行4列表示这个矩阵。
 

Output
对于每组输入输出一个正整数表示最少的移动步数,大于5则输出-1.
 

Sample Input
  
  
2 1 2 3 4 1 2 3 4 1 2 3 4 2 3 4 1 4 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4
 

Sample Output
  
  
1 1


求H函数:

      最后的状态为:

        1 1 1 1

        3 3 3 3

        4 4 4 4

        2 2 2 2

如上,每列一致,也就是说每行的数字一样,

那么统计每行的数字相同最多有k个, 则只少需要移动4-k个数字来使得一样。

一次状态的改变最多可以改变4个数字, 所以最后的结果为 

  UP {min(每行数字相同需要改变数字个数和 ,每行数字相同需要改变数字个数和  ) / 4 }  


import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {

	public static void main(String[] args) {
		new HDU2234().solve();
	}
}

class HDU2234 {

	InputReader in = new InputReader(System.in);
	PrintWriter out = new PrintWriter(System.out);
	
	int[][] a = new int[5][5] ;

	void solve(){
		int t = in.nextInt() ;
		while(t-- > 0){
			for(int i = 1 ; i <= 4 ; i++)
				for(int j = 1 ; j <= 4 ; j++) a[i][j] = in.nextInt() ;
			
			for(deep = 0 ; deep <= 5 ; deep++){
				if(dfs(0))  break ;
			}
			
		    out.println(deep > 5 ? -1 : deep) ;
		}
		out.flush() ; 
	}
	
	int deep ;
	
	boolean dfs(int step){
		if(step + h() > deep) return false ;
		if(endRow() || endColum()) return true ;
		
		for(int row = 1 ; row <= 4 ; row++){
			moveRowLeft(row) ;
			if(dfs(step + 1)) return true ;
			moveRowRight(row) ;
			
			moveRowRight(row) ;
			if(dfs(step + 1)) return true ;
			moveRowLeft(row) ;
		}
		
		for(int col = 1 ; col <= 4 ; col++){
			moveColumUp(col) ;
			if(dfs(step + 1)) return true ;
			moveColumDown(col) ;
			
			moveColumDown(col) ;
			if(dfs(step + 1)) return true ;
			moveColumUp(col) ;
		}
		
		return false ;
	}
	
	int h(){
		int[] num = new int[5] ;
		int mx , rowSum = 0 , colSum = 0 ;
		for(int i = 1 ; i <= 4 ; i++){
			Arrays.fill(num , 0) ;
			for(int j = 1 ; j <= 4 ; j++){
				num[a[i][j]]++ ;
			}
			mx = 0 ;
			for(int k = 1 ; k <= 4 ; k++)
				mx = Math.max(mx , num[k]) ;
			rowSum += 4 - mx ;		
		}
		
		for(int i = 1 ; i <= 4 ; i++){
			Arrays.fill(num , 0) ;
			for(int j = 1 ; j <= 4 ; j++){
				num[a[j][i]]++ ;
			}
			mx = 0 ;
			for(int k = 1 ; k <= 4 ; k++)
				mx = Math.max(mx , num[k]) ;
			colSum += 4 - mx ;		
		}
		
		return ( Math.min(rowSum, colSum) + 3 ) / 4 ;
	}
	
	boolean endRow(){
		for(int j = 1 ; j <= 4 ; j++){
			for(int i = 2 ; i <= 4 ; i++){
				if(a[i][j] != a[1][j]) return false ;
			}
		}
		return true ; 
	}
	
	boolean endColum(){
		for(int i = 1 ; i <= 4 ; i++){
			for(int j = 2 ; j <= 4 ; j++){
				if(a[i][j] != a[i][1]) return false ;
			}
		}
		return true ;
	}
	
	void moveRowLeft(int id){
		int k = a[id][1] ;
		for(int i = 1 ; i <= 3 ; i++) a[id][i] = a[id][i+1] ;
		a[id][4] = k ;
	}
	
	void moveRowRight(int id){
		int k = a[id][4] ;
		for(int i = 4 ; i >= 2 ; i--) a[id][i] = a[id][i-1] ;
		a[id][1] = k ;
	}
	
	void moveColumUp(int id){
		int k = a[1][id] ;
		for(int i = 1 ; i <= 3 ; i++) a[i][id] = a[i+1][id] ;
		a[4][id] = k ;
	}
	
	void moveColumDown(int id){
		int k = a[4][id] ;
		for(int i = 4 ; i >= 2 ; i--) a[i][id] = a[i-1][id] ;
		a[1][id] = k ;
	}
	
}

class InputReader {
	public BufferedReader reader;
	public StringTokenizer tokenizer;

	public InputReader(InputStream stream) {
		reader = new BufferedReader(new InputStreamReader(stream), 32768);
		tokenizer = new StringTokenizer("");
	}

	private void eat(String s) {
		tokenizer = new StringTokenizer(s);
	}

	public String nextLine() {
		try {
			return reader.readLine();
		} catch (Exception e) {
			return null;
		}
	}

	public boolean hasNext() {
		while (!tokenizer.hasMoreTokens()) {
			String s = nextLine();
			if (s == null)
				return false;
			eat(s);
		}
		return true;
	}

	public String next() {
		hasNext();
		return tokenizer.nextToken();
	}

	public int nextInt() {
		return Integer.parseInt(next());
	}

	public long nextLong() {
		return Long.parseLong(next());
	}

	public double nextDouble() {
		return Double.parseDouble(next());
	}

	public BigInteger nextBigInteger() {
		return new BigInteger(next());
	}

}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值