資料結構——導通電路板問題(排序)
阿新 • • 發佈:2018-12-17
有一塊佈滿器件的電路板,器件共N行M列。每個器件只有兩種狀態,經一次鐳射照射後狀態反轉。
初始時,器件的狀態隨機。鐳射的位置在每列器件的最上方,這意味著照射一次,當前列中的所有器件的狀態全部反轉。(鐳射可以多次照射同一列。)
當一行中的所有器件全為1時,本行處於導通狀態。
給定一塊電路板,並指定鐳射照射次數,求最大導通行數。
限定:3≤行數N≤100,3≤列數M≤20,1≤鐳射照射次數K≤M。
提示:
電路板可以使用0/1矩陣表示,0表示不導通態,1表示導通態。
輸入:N行×M列的0/1矩陣,及列反轉次數K。求經過K次列反轉後行全為1的最大行數。其中:3≤N≤100,3≤M≤20,1≤K≤M。必須反轉K次,同一列可以多次反轉。
例如,輸入是下圖所示的0/1矩陣,k=3。
輸出2,即反轉3列,得到最多2行導通。
考慮K的奇偶性及一行中0的個數的奇偶性。最終變為排序問題。
程式碼(vs2010):
#include<iostream> using namespace std; static int N; static int M; static int K; int ou[100]; int ou1[100]; int ji[100]; int ji1[100]; int sum[100]; int lin[100]; int m=0,n=0,k=0; void print(char **a){ for(int i=0;i<N;i++){ for(int j=0;j<M;j++){ cout<<a[i][j]; } cout<<endl; } cout<<endl; } void judge0(char **a,int *l){ for(int i=0;i<N;i++){ int temp=0; for(int j=0;j<M;j++){ if(a[i][j]=='0')temp++; } l[i]=temp; } } /*void turn(char*a){ for(int i=0;i<N;i++){ if(a[i]=='0'){ a[i]='1'; } else a[i]='0'; } }*/ void Merge(int *r,int *rf, int i, int m, int n) { int j,k; for(j=m+1,k=i; i<=m && j <=n ; ++k){ if(r[j] < r[i]) rf[k] = r[j++]; else rf[k] = r[i++]; } while(i <= m) rf[k++] = r[i++]; while(j <= n) rf[k++] = r[j++]; } void MergeSort(int *r, int *rf, int lenght) { int len = 1; int *q = r ; int *tmp ; while(len < lenght) { int s = len; len = 2 * s ; int i = 0; while(i+ len <lenght){ Merge(q, rf, i, i+ s-1, i+ len-1 ); //對等長的兩個子表合併 i = i+ len; } if(i + s < lenght){ Merge(q, rf, i, i+ s -1, lenght -1); //對不等長的兩個子表合併 } tmp = q; q = rf; rf = tmp; //交換q,rf,以保證下一趟歸併時,仍從q 歸併到rf } } void div(int *l){ for(int i=0;i<N;i++){ if(l[i]%2==0){ ou[m]=l[i]; m++; } else{ ji[n]=l[i]; n++; } } m--; n--; MergeSort(ou,ou1,m); MergeSort(ji,ji1,n); /*for(int i=0;i<m;i++){ for(int j=i;j<m;j++){ if(ou[i]>ou[j]){ int temp=ou[i]; ou[i]=ou[j]; ou[j]=temp; } } } for(int i=0;i<n;i++){ for(int j=i;j<n;j++){ if(ji[i]>ji[j]){ int temp=ji[i]; ji[i]=ji[j]; ji[j]=temp; } } }*/ } void panduan(int *l){ div(l); if(K%2==0){ for(int i=0;i<m;i++){ if(K>=ou1[i]){ lin[k]=ou1[i]; } k++; } k--; } else{ for(int i=0;i<n;i++){ if(K>=ji1[i]){ lin[k]=ji1[i]; } k++; } k--; } } void fanzhuan(char**a,char**b,int *l){ panduan(l); int he=0,um=0; int max=0; //if(K>lin[M]){K=lin[M];} if(K<lin[0]){cout<<"翻轉"<<K<<"導通行數為0";} else{ for(int i=k;i>=0;i--){ for(int j=N-1;j>=0;j--){ if(l[j]==lin[i]){ l[j]+=1; for(int x=0;x<N;x++){ for(int y=0;y<M;y++){ b[x][y]=a[x][y]; } } for(int x=0;x<M;x++){ if(b[j][x]=='0'){ for(int g=0;g<N;g++){ if(b[g][x]=='0'){ b[g][x]='1'; } else b[g][x]='0'; } } } print(b); bool t=1; for(int x=0;x<N;x++){ for(int y=0;y<M;y++){ if(b[x][y]=='0')t=0; } if(t){ he++; } t=1; } sum[um]=he; um++; he=0; } } } for(int x=0;x<um;x++){ if(sum[x]>=max)max=sum[x]; } cout<<"翻轉"<<K<<"次後最大導通行數為"<<max<<endl; } } void main(){ char **a; char**b; int *l; cout<<"請輸入電路板的行數N(3<=N<=100):"; cin>>N; cout<<"請輸入電路板的列數M(3<=M<=20): "; cin>>M; a=new char*[N]; b=new char*[N]; l=new int[N]; for(int i=0;i<N;i++){ a[i]=new char[M]; b[i]=new char[M]; } cout<<"請輸入電路板佈局:"<<endl; for(int i=0;i<N;i++){ for(int j=0;j<M;j++){ cin>>a[i][j]; } } cout<<"請輸入翻轉次數K(1<=K<=M):"; cin>>K; judge0(a,l); /*for(int i=0;i<N;i++){ cout<<l[i]<<" "; }*/ cout<<endl; fanzhuan(a,b,l); system("pause"); }