1. 程式人生 > >資料結構——導通電路板問題(排序)

資料結構——導通電路板問題(排序)

有一塊佈滿器件的電路板,器件共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");
}