1. 程式人生 > >T:電路板導通問題(C++)

T:電路板導通問題(C++)

問題描述:

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

1 0 0 1 0
1 1 0 0 0
0 1 1 1 0
0 0 0 1 1
1 0 1 0 1
1 1 0 0 0

輸出:2,即反轉3列,得到最多2行導通。

考慮K的奇偶性及一行中0的個數的奇偶性。最終變為排序問題。

 

實現程式碼:

/*測試環境:VS2017*/

#include<iostream>
#include<math.h>

using namespace std;

int M,N,k;
int **a,**b,*num_0,*odd,*even,*com;
int MaxCount=0,num=0;

void GetData()//依據輸入確定M和N的大小,並讀入資料
{
	cout << "請依次輸入行數N、列數M、鐳射照射次數k(3≤N≤100,3≤M≤20,1<=k<=M):";
	cin >> N >> M>>k;
	a = new int*[N];
	b = new int*[N];
	for (int i = 0; i < N; i++)
	{
		a[i] = new int[M];
		b[i] = new int[M];
	}

	cout << "請輸入資料陣列:"<<endl;
	for(int i=0;i<N;i++)
		for (int j = 0; j < M; j++)
		{
			cin >> a[i][j];
			b[i][j] = a[i][j];
		}
}

inline void Trans(int **arr,int m)//列反轉
{
	int n = N;
	while (n--)
		arr[n][m] = abs(arr[n][m] - 1);
}

int Judge(int **arr)//計算導通行數
{
	int count=0;
	for (int i = 0; i < N; i++)
	{
		bool L = true;
		for (int j = 0; j < M; j++)
		{
			if (arr[i][j] == 0)
			{
				L = false;
				break;
			}
		}
		if(L)
			count++;
	}
	return count;
}

void selectSort(int*arr,int len)
{
	int index,temp;
	for (int i = 0; i < len - 1; i++)
	{
		temp = arr[i];
		index = i;
		for (int j = i + 1; j < len; j++)
		{
			if (arr[j] < arr[index])
				index = j;
		}
		arr[i] = arr[index];
		arr[index] = temp;
	}
}

void Count(int**arr)//計數每行0的個數存在num_0裡,0的個數為偶數且小於k的存於even,類似的奇數存於odd裡
{
	num_0 = new int[N];
	odd = new int[N];
	even = new int[N];
	com = new int[N];
	
	int count0 = 0, count1 = 0;

	for (int i = 0; i < N; i++)
	{	
		int temp=0;
		for (int j = 0; j < M; j++)
			if (arr[i][j] == 0)
				temp++;
		num_0[i] = temp;
	}

	for (int i = 0; i < N; i++)
	{
		if (num_0[i] <= k && num_0[i] % 2 == 0)
			even[count0++] = num_0[i];
		if (num_0[i] <= k && num_0[i] % 2 == 1)
			odd[count1++] = num_0[i];
	}
	selectSort(even, count0 );
	selectSort(odd, count1 );
	if (k % 2 == 0)
	{
		for (int i = 0; i < count0; i++)
			com[i] = even[i];
		num = count0;
	}
	if (k % 2 == 1)
	{
		for (int i = 0; i < count1; i++)
			com[i] = odd[i];
		num = count1;
	}
}

void GetResult()
{
	for(int i=0;i<num;i++)
		for (int j = 0; j < N; j++)
		{
			if (com[i] == num_0[j])
			{
				for (int n = 0; n < N; n++)
					for (int m = 0; m < M; m++)
						b[n][m] = a[n][m];
				for(int m=0;m<M;m++)
					if (b[j][m] == 0)
						Trans(b, m);
			}
			MaxCount = (MaxCount >= Judge(b) ? MaxCount : Judge(b));
		}
	cout << "最大導通數為:" << MaxCount << endl;
}

int main()
{
	GetData();
	Count(a);
	GetResult();	
	system("pause");
}

注:程式碼中的排序並不是必要的,不排序也能直接實現;另一種方法是把篩選後的每一行都轉換成十進位制後再排序,找出相等的數的最大個數即為最大導通數。