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");
}

注:代码中的排序并不是必要的,不排序也能直接实现;另一种方法是把筛选后的每一行都转换成十进制后再排序,找出相等的数的最大个数即为最大导通数。

猜你喜欢

转载自blog.csdn.net/Hodge_Z/article/details/85050022