问题描述:
有一块布满器件的电路板,器件共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");
}
注:代码中的排序并不是必要的,不排序也能直接实现;另一种方法是把筛选后的每一行都转换成十进制后再排序,找出相等的数的最大个数即为最大导通数。