計算機演算法設計與分析1-4 金幣陣列問題
阿新 • • 發佈:2018-12-13
問題描述:有m*n枚金幣在桌面上排列成一個m行n列的金幣陣列。每一枚金幣或正面朝上,或背面朝上。用數字表示金幣狀態,0表示正面朝上,1表示背面朝上。
金幣陣列遊戲的規則是:
(1)每次將任一行金幣翻過來放在原來的位置上。
(2)每次可以任選2列,交換這2列金幣的位置。
任務:給定金幣的初始狀態和目標狀態,程式設計計算按金幣遊戲規則,將金幣排列從初始狀態變換到目標狀態所需的最少變換次數。
這題我一開始想著先做一遍行反轉(這一行所有元素在初始和目標矩陣的都不同時),然後再做列交換,然而寫了半天也不知道這個策略怎麼寫,從前往後走一遍的話不能保證最優。
說實話題解的做法我不太理解原理,但大致也覺得這麼是對的。
題解中n+m+1設為最大交換次數,我感覺最大也就是m + n/2,不知道這樣理解對不對。
具體步驟:
1.將初始矩陣所有列依次放到第一列(我的理解是這樣,第一是因為這裡的規則是進行行反轉,列交換,如果是列反轉,行交換的話,就是所有行依次放到第一行了, 第二是後面從前往後檢視是否有列相同或者交換可得到,這在某種意義上進行了列舉,每一種可能都進行了嘗試,以每一列為基準進行嘗試,這與第二步也有關)
2. 對比當前第一列,也就是交換之前的1到n中某一列的元素是不是和目標矩陣一樣,不一樣就進行行反轉
3.從前到後看每一列,如果當前列與目標矩陣中的當前列相同或者可以交換得到,那麼就計算次數並與上次結果比較大小,如果不同且無法交換得到,那麼這種嘗試是失敗的(這裡注意最後比較的時候是從當前列而不是下一列,為了判斷這一列是不是相同)
下面是程式碼
#include<bits/stdc++.h> using namespace std; #define maxn 110 int terms,n,m,inti[maxn][maxn],des[maxn][maxn],tep[maxn][maxn]; int cnt=0; void transfer_column(int col)//tep { for(int i=1;i<=n;i++) tep[col][i]=tep[col][i]^1; cnt++; } void transfer_row(int rowa,int rowb)//tep { for(int i=1;i<=m;i++) { tep[i][rowa]+=tep[i][rowb]; tep[i][rowb]=tep[i][rowa]-tep[i][rowb]; tep[i][rowa]-=tep[i][rowb]; } if(rowa!=rowb) cnt++; } bool same_row(int rowa,int rowb)//tep && des { for(int i=1;i<=m;i++) if(tep[i][rowa]!=des[i][rowb]) return false; return true; } void copymatrix()//give inti to tep { for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) tep[i][j]=inti[i][j]; } void setup() { scanf("%d%d",&m,&n); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) scanf("%d",&inti[i][j]); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) scanf("%d",&des[i][j]); } int main() { freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); scanf("%d",&terms); int res=m+n+1; while(terms--) { setup(); for(int i=1;i<=n;i++) { cnt=0; res=n+m+1; int flag=0; copymatrix(); if(i-1) transfer_row(1,i); for(int j=1;j<=m;j++) if(tep[j][1]!=des[j][1]) transfer_column(j); for(int j=1;j<=n;j++)//注意 { flag=0; for(int k=j;k<=n;k++)//這裡是從j開始而不是j+1,是為了比較這一列和目標矩陣中是否相同 if(same_row(j,k)) {transfer_row(j,k),flag=1;break;} if(!flag) break; } if(flag && cnt<n+m+1) res=res>cnt?cnt:res; } printf("%d\n",res==m+n+1?-1:res); } return 0; }