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列表示这个矩阵。
对于每组数据输入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());
}
}