金幣陣列問題

2021-06-12 10:15:48 字數 2848 閱讀 6656

問題描述:

有m x n (m<=100, n<=100 ) 個金幣在桌面上排成乙個m行n 列的金幣陣列。每一枚金幣或正面朝上或背面朝上。用數字表示金幣狀態,0表示金幣正面朝上,1 表示背面朝上。金幣陣列遊戲的規則是:

(1)每次可將任一行金幣翻過來放在原來的位置上;

(2)每次可任選2 列,交換這2 列金幣的位置。

程式設計任務:

給定金幣陣列的初始狀態和目標狀態,程式設計計算按金幣遊戲規則,將金幣陣列從初始狀態變換到目標狀態所需的最少變換次數。

資料輸入:

由檔案input.txt給出輸入資料。檔案中有多組資料。檔案的第1行有1 個正整數k,表示有k 組資料。每組資料的第1 行有2 個正整數m 和n。以下的m行是金幣陣列的初始狀態,每行有n 個數字表示該行金幣的狀態,0 表示金幣正面朝上,1 表示背面朝上。接著的

m行是金幣陣列的目標狀態。

結果輸出:

將計算出的最少變換次數按照輸入資料的次序輸出到檔案output.txt。相應資料無解時輸出-1。

輸入檔案示例 輸出檔案示例

input.txt 

24 3

1 0 1

0 0 0

1 1 0

1 0 1

1 0 1

1 1 1

0 1 1

1 0 1

4 31 0 1

0 0 0

1 0 0

1 1 1

1 1 0

1 1 1

0 1 1

1 0 1

output.txt2-1

問題解析:

題目要求找出最少的變換次數,我們可以窮舉每一種變換,記錄變換次數,然後從中選取變換次數最少的變換方法。

問題的關鍵是如何尋找一種高效、快速的窮舉方法。題目給出兩種變換規則,1、行變換:可以將每行的元素由0變為1或者由1變為0

2、列變換,交換兩列元素。有兩種窮舉方法,1.以行變換為主,列變換基於行變換  2.列變換為主,行變換基於列變換。可以發現,第二種變換,即以列變換為主,相對簡單。如果讓每一列與第一列進行交換後,然後進行行變換,即比較初始狀態進行列交換後的第一列和目標狀態的第一列,如果初始狀態的第一列的某一行的元素和目標狀態相應的元素不同,則將初始狀態的該行進行行變換。進行行變換之後,初始狀態第一列和目標狀態第一列完全相同,以後就不能再進行行變換,只需要進行列變換,從初始狀態中分別尋找和目標狀態的第2至n列相同的列,並進行列變換。

源程式如下:

#include

#include

#include

#define inf 1<<30

using namespace std;

/*將矩陣a的第col行進行行變換*/

void transfer_row(int array,int n)

/*交換矩陣a的i和j列*/

void swap_columns(int **a,int m,int n,int i,int j)

}/*比較矩陣a的第col_a列和矩陣b的第col_b是否相等*/

int compare_column(int **a,int **b,int m,int n,int col_a,int col_b)

return 1;

}void copy_array(int** dest,int **src,int m,int n )

/**尋找將原始矩陣a變換到目標矩陣b的最少變換次數,如果不能將a變換到b,那麼返回-1*/

int find(int **a,int **b,int m,int n)

}//int k=0;

/**從a中一次尋找相應的某些列使得這些列一次和b中的第2到第n列相等,

如果查詢成功,則說明此種變換可以達到目標狀態,然後將此種變換所花費的變換次數和當前最有變換次數best比較

如果小於best,則將best更新此種變換的花費的變換次數

*/for(int j=1;j

flag=1;

break;}}

if(flag==0)

break;

//count=0;

}if(flag==1&&best>count)

best=count;

count=0;

copy_array(a,tmp,m,n);

}if(bestreturn best;

else return -1;

}int main()

for(int i=0;ifor(int j=0;jin>>a[i][j];

for(int i=0;ifor(int j=0;jin>>b[i][j];

int res=find(a,b,m,n);

cout<

下面是一種錯誤的方法:

根據題目給出的金幣變換規則,以及每行對應的每一列元素要麼為0要麼為1,可以發現以下規律:

1、如果初始狀態經過若干步變換,能夠轉換成目標狀態,則初始狀態的第i行和目標狀態的第i行的1的個數要麼相等要麼兩者之和等於n(列的個數)。

因此,首先可以對初始狀態的每行進行預處理,將初始狀態的第i行和目標狀態的第i行的1進行比較,如果兩者之和為n,則將初始狀態進行行變換,如果兩者1的個數相等,則不變換,如果既不相等,兩者之和也不等於n,則程式直接返回-1,結束執行,初始狀態不可能轉換成目標狀態。(此處分析忽略了一點,如果列n為偶數,並且初始狀態的第i行和目標狀態的第i行的1的個數分別為n/2,這時就可能出錯,因為這種情況滿足兩者1的個數相等和兩者之和為n這兩種情況,就沒法確定該不該進行行變換)

2、初始狀態經過行預處理之後,再進行列的處理。從初始狀態的列中找出和目標狀態第一列相同的列,然後初始狀態中的此列和初始狀態的第一列交換,如何初始狀態中沒有和目標狀態第一列相同的列,則終止程式執行返回-1。按照第一列的方法依次進行第2列

到第n列的處理。

金幣陣列問題

有m n枚金幣在桌面上排成乙個金幣陣列。每乙個金幣正面朝上,或背面朝上,分別用0和1表示。金幣陣列遊戲的規則是 1 每次可將任一行金幣翻過來放在原來的位置上 2 每次可任選2列,交換這2列金幣的位置。給定金幣的初始狀態和目標狀態,計算按金幣遊戲規則,將金幣陣列從初始狀態變換到目標狀態所需的最少變換次...

金幣陣列問題

有m n枚金幣在桌面上排成乙個金幣陣列。每乙個金幣正面朝上,或背面朝上,分別用0和1表示。金幣陣列遊戲的規則是 1 每次可將任一行金幣翻過來放在原來的位置上 2 每次可任選2列,交換這2列金幣的位置。給定金幣的初始狀態和目標狀態,計算按金幣遊戲規則,將金幣陣列從初始狀態變換到目標狀態所需的最少變換次...

金幣陣列問題

1.問題描述 有mxn枚金幣 m,n 100 在桌面上擺成乙個m行n列的陣列,每一枚金幣正面朝上或者背面朝上,用數字0和1表示金幣的狀態。遊戲規則 每次將任意一行金幣翻過來 每次可任意交換兩列 演算法設計 給定陣列初始狀態,目標狀態,按遊戲規則計算從初始狀態到目標狀態需要的最少變換次數 資料輸入 從...