算法设计与分析: 6-22 行列变换问题

6-22 行列变换问题


问题描述

给定 2 个 m×n m × n 方格阵列组成的图形 A 和 B,每个方格的颜色为黑色或白色。行列变换问题的每一步变换可以交换任意 2 行或 2 列方格的颜色,或者将某行或某列颠倒。上述每次 变换算作一步。试设计一个算法,计算最少需要多少步,才能将图形 A 变换为图形 B。

行列变换

对于给定的 2 个方格阵列,编程计算将图形 A 变换为图形 B 的最少变换次数。

数据输入:
第 1 行有 2 个正整数 m 和 n。以下的 m 行是方格阵列的初始状态 A,每行有 n 个数字表示该行方格的状态,0 表示白色,1 表示黑色。接 着的 m 行是方格阵列的目标状态 B。


Java

package Chapter6FenZhiXianJieFa;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class HangLieBianHuan {

    private static final int MaxSize = 1<<25;
    private static int m,n;
    private static int sour,dest;
    private static int[] row,col;
    private static int[] hash = new int[MaxSize];
    private static int[] ans = new int[MaxSize];
    private static int X;

    public static void main(String[] args){
        Scanner input = new Scanner(System.in);

        while (true){
            if(!init(input)){
                System.out.println("No Solution!");
                return;
            }
            if(fifobb()){
                System.out.println(hash[dest]);
                output(dest);
            }
        }
    }

    private static boolean init(Scanner input){
        int i;
        int a=0,b=0;

        m = input.nextInt();
        n = input.nextInt();

        row = new int[m];
        col = new int[n];

        String[] src = new String[m];
        String[] des = new String[m];
        char[] srcChars = new char[m*n];
        char[] desChars = new char[m*n];

        for(i=0; i<m; i++){
            src[i] = input.next();
            System.arraycopy(src[i].toCharArray(),0,srcChars,n*i,n);
        }

        for(i=0; i<m; i++){
            des[i] = input.next();
            System.arraycopy(des[i].toCharArray(),0,desChars,n*i,n);
        }

        for(sour=i=0; i<m*n; i++) {sour|=(srcChars[i]-'0')<<i; a+=srcChars[i]-'0';}
        for(dest=i=0; i<m*n; i++) {dest|=(desChars[i]-'0')<<i; b+=desChars[i]-'0';}

        return a==b;
    }

    private static boolean fifobb(){
        Queue<Integer> Q = new LinkedList<>();
        int E = 0;
        int N = 0;
        for(int i=0; i<MaxSize; i++) hash[i]=-1;
        hash[sour] = 0;
        Q.add(sour);
        while (!Q.isEmpty()){
            E = Q.poll();
            for(int i=0; i<m-1; i++)
                for(int j=i+1; j<m; j++){
                    N = rowswap(E,i,j);
                    if(hash[N] == -1){
                        hash[N] = hash[E]+1;
                        ans[N] = E;
                        Q.add(N);
                    }
                }
            for(int i=0; i<n-1; i++)
                for(int j=i+1; j<n; j++){
                    N = colswap(E,i,j);
                    if(hash[N] == -1){
                        hash[N] = hash[E]+1;
                        ans[N] = E;
                        Q.add(N);
                    }
                }

            for(int i=0; i<m; i++){
                N = revrow(E,i);
                if(hash[N] == -1){
                    hash[N] = hash[E]+1;
                    ans[N] = E;
                    Q.add(N);
                }
            }
            for(int i=0; i<n; i++){
                N = revcol(E,i);
                if(hash[N] == -1){
                    hash[N] = hash[E]+1;
                    ans[N] = E;
                    Q.add(N);
                }
            }
            if(hash[dest] != -1) return true;
        }

        return false;
    }

    private static int rowswap(int x, int i, int j){
        rowx(x);
        swap(row,i,j);
        X = x;
        rowy();
        x = X;

        return x;
    }

    private static int colswap(int x, int i, int j){
        colx(x);
        swap(col,i,j);
        X = x;
        coly();
        x = X;

        return x;
    }

    private static void swap(int[] x, int i, int j){
        int tmp = x[i];
        x[i] = x[j];
        x[j] = tmp;
    }

    private static int revrow(int x, int i){
        rowx(x);

//        reve(row[i],n);
        reve(row,i,n);

        X = x;
        rowy();
        x = X;
//        rowy(x);

        return x;
    }

    private static int revcol(int x, int i){
        colx(x);

        reve(col,i,m);
//        reve(col[i],m);

        X = x;
        coly();
        x = X;
//        coly(x);

        return x;
    }

    private static void rowx(int x){
        for(int i=0; i<m; i++){
            int y=1; row[i]=0;
            for(int j=0; j<n; j++){
                if((x&1) > 0) row[i]|=y;
                y<<=1; x>>=1;
            }
        }
    }

    private static void colx(int x){
        for(int j=0; j<n; j++) col[j]=0;
        int y=1;
        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++){
                if((x&1) > 0) col[j]|=y;
                x>>=1;
            }
            y<<=1;
        }
    }

    private static void rowy(){
        X=0;
        for(int i=0,z=1; i<m; i++){
            int y = row[i];
            for(int j=0; j<n; j++){
                if((y&1) > 0) X|=z;
                z<<=1; y>>=1;
            }
        }
    }

    private static void coly(){
        X=0;
        for(int i=0,z=1; i<m; i++){
            for(int j=0; j<n; j++){
                if((col[j]&1) > 0) X|=z;
                col[j]>>=1; z<<=1;
            }
        }
    }

    private static void reve(int[] x, int i, int k){
        int y=0,z=1<<(k-1);
        for(int j=0; j<k; j++){
            if((x[i]&1) > 0) y|=z;
            z>>=1; x[i]>>=1;
        }
        x[i] = y;
    }

    private static void output(int N){
        if(N == sour){
            System.out.println();
            outb(N);
            return;
        }
        output(ans[N]);
        System.out.println();
        outb(N);
    }

    private static void outb(int x){
        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++){
                if((x&1) > 0) System.out.print(1);
                else System.out.print(0);
                x /= 2;
            }
            System.out.println();
        }
    }
}

Input & Output

4 4
1010
0100
0010
1010
1010
0000
0110
0101
2

1010
0100
0010
1010

1010
0000
0110
1010

1010
0000
0110
0101


4 4
1111
0000
1111
0000
0000
1111
0000
1111
2

1111
0000
1111
0000

0000
1111
1111
0000

0000
1111
0000
1111




9 2
01
11
00
10
11
01
00
01
00
10
00
01
11
01
00
01
00
11
5

01
11
00
10
11
01
00
01
00

11
01
00
10
11
01
00
01
00

11
00
01
10
11
01
00
01
00

11
00
01
10
11
01
01
00
00

10
00
01
11
11
00
01
00
01

10
00
01
11
01
00
01
00
11

Reference

王晓东《计算机算法设计与分析》

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值