2019.11.26
一背景:
老板心血来潮找来C试题试试我们的深浅,Google 原题源于某论坛但暂时未解答,排列组合算法实现是关键,通过大佬指导,利用C语言排列组合实现。
二 题目要求

题目解释:程序要求输入行数1-100和列数1-10 的数组(数组元素为0或1),每次只翻动一行或者一列,即不允许翻动单个元素,使得最终数组中的1最多。
example:
三. C语言实现思路
开发环境visual studio 2017:
1.单行单列翻转容易处理,0多余1翻转,反之不翻转。
2.多行多列比较麻烦,开始认为只翻转0多余1的行和列就可以,但是发现0和1相等或者1多余0的行列的翻转会互相影响,有的组合翻转可以使得1的个数增加,所以不能简单考虑,必须组合翻转判断是否可取。
四. Source code
1.C语言排列组合测试code,可以用两个for循环实现。
//Source code
#include <stdio.h>
#include <stdlib.h>
int main()
{
int array[3] = { 0,1,2 };
int count = 3;
int i, j;
for (i = 1; i < (1 << count); i++)
{
printf("jeet test loop =%d\n", i);
for (j = 0; j < count; j++)
{
if (i & (1 << j))
{
printf("jeet test array[j]=%d\n", array[j]);
}
}
}
return 0;
}
#endif
测试log
jeet test loop =1
jeet test array[j]=0
jeet test loop =2
jeet test array[j]=1
jeet test loop =3
jeet test array[j]=0
jeet test array[j]=1
jeet test loop =4
jeet test array[j]=2
jeet test loop =5
jeet test array[j]=0
jeet test array[j]=2
jeet test loop =6
jeet test array[j]=1
jeet test array[j]=2
jeet test loop =7
jeet test array[j]=0
jeet test array[j]=1
jeet test array[j]=2
G:\little_fish\fish_c_lesson\jeet_c_practise\2019_1119\coinFliping\coinFliping\Debug\coinFliping.exe (进程 7696)已退出,返回代码为: 0。
若要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口...
2. 题目实现source code
//source code
//coin flipping easy game
//Author: Jeet.Liu
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <time.h>
#include <math.h>
#define DEBUG_LOG 0
int rows, columns;
int* rowequalArray;
int* columnequalArray;
int* coinArray;
int* backcoinArray;
int* tempcoinArray;
void dataCheck(void);
void rowTrans(int rowtransNum);
void columnTrans(int columntransNum);
int rowSum(int rowsumNum);
int columnSum(int columnsumNum);
int rowabsSum(void);
int columnabsSum(void);
int rowandcoluSum(void);
int inputInteger(const char* prompt, int max, int min);
void inputArray(int* tempArr, int tempRow, int tempColumn);
void outputArray(int* tempArr, int tempRow, int tempColumn);
void arrayConvert(int* tempArr, int tempRow, int tempColumn);
void arrayRestore(int* tempArr, int tempRow, int tempColumn);
void onelineTrans(int* tempArr, int tempRow, int tempColumn);
int main()
{
int i, j;
rows = inputInteger("行数 请输入1~100之间的整数:", 100, 1);
printf("用户输入的行数是:%d\n", rows);
columns = inputInteger("列数 请输入1~10之间的整数:", 10, 1);
printf("用户输入的列数是:%d\n", columns);
//动态分配内存
coinArray = (int *)malloc(sizeof(int) * rows * columns);//二维数组一次性分配内存
rowequalArray = (int *)malloc(sizeof(int) * rows);
columnequalArray = (int *)malloc(sizeof(int) * columns);
backcoinArray = (int *)malloc(sizeof(int) * rows * columns);
tempcoinArray = (int *)malloc(sizeof(int) * rows * columns);
//笔误内存分配不够溢出
//自动输入数组测试:
#if 1
srand((unsigned)time(NULL));//srand()就是给rand()提供种子seed
for (i = 0; i < rows; i++)
{
for (j = 0; j < columns; j++)
{
*((coinArray + i * columns) + j) = rand() % 2;//对2取余得到就是0或者1
}
}
#endif
//手动输入数组测试:
//inputArray(coinArray, rows, columns);
printf("输入的数列是:\n");
outputArray(coinArray, rows, columns);
//数组元素0转换-1
arrayConvert(coinArray, rows, columns);
dataCheck();
//数组元素转换0
arrayRestore(coinArray, rows, columns);
//转换后输出测试
printf("转换后的数列是:\n");
outputArray(coinArray, rows, columns);
//释放动态开辟的空间
free(coinArray);
free(rowequalArray);
free(columnequalArray);
free(backcoinArray);
free(tempcoinArray);
return 0;
}
//输入检查函数:
int inputInteger(const char* prompt, int max, int min)
{
int result = 0;
int inputCount = 0;
do
{
printf("%s", prompt);
rewind(stdin);
inputCount = scanf_s("%d", &result);
} while (inputCount == 0 || result > max || result < min);
return result;
}
void inputArray(int* tempArr, int tempRow, int tempColumn)
{
int i;
int j;
int countColumns = 0;
countColumns = tempColumn;
for (i = 0; i < tempRow; i++)
{
for (j = 0; j < tempColumn; j++)
{
printf("tempArr[%d][%d]=", i, j);
*((tempArr + i * countColumns) + j) = inputInteger(" ", 1, 0);
}
}
}
void outputArray(int* tempArr, int tempRow, int tempColumn)
{
int i;
int j;
int arraySum = 0;
for (i = 0; i < tempRow; i++)
{
for (j = 0; j < tempColumn; j++)
{
arraySum += *(tempArr + i * tempColumn + j);
printf("%d ", *(tempArr + i * tempColumn + j));
}
printf("\n");
}
printf("head 最多个数为:%d\n", arraySum);
}
void dataCheck(void)
{
int i, j, m, n;
int oldVal = 0;
int newVal = 0;
int changedFlag = 0;
int loopFlag = 0;
int rowequalNum = 0;
int columnequalNum = 0;
//单行
if (1 == rows || 1 == columns)
{
onelineTrans(coinArray, rows, columns);
}
//多行
else
{
do
{
//清除循环flag
loopFlag = 0;
//行转换
for (i = 0; i < rows; i++)
{
if (rowSum(i) < 0)
{
rowTrans(i);
#if DEBUG_LOG
arrayRestore(coinArray, rows, columns);
outputArray(coinArray, rows, columns);
arrayConvert(coinArray, rows, columns);
#endif
loopFlag = 1; //有转换设flag
}
}
rowequalNum = 0;
changedFlag = 0; //清flag 和计数
for (i = 0; i < rows; i++)
{
//if (0 == rowSum(i)) //仅仅是0和1个数一样的组合
{
rowequalArray[rowequalNum++] = i; //行号保存在数组中
}
}
oldVal = columnabsSum(); //转换各列和的绝对值之和
if (rowequalNum)
{
for (m = 1; m < (1 << rowequalNum); m++) //排列组合
{
//backcoinArray = coinArray; //错误示范,指针随便用会崩掉
memcpy(backcoinArray, coinArray, rows * columns * sizeof(int)); //备份数组
for (n = 0; n < rowequalNum; n++)
{
if (m & (1 << n))
{
rowTrans(*(rowequalArray + n)); //转换指定行
}
}
newVal = columnabsSum();//转换后各列和的绝对值之和
if (newVal > oldVal)
{
oldVal = newVal;
memcpy(tempcoinArray, coinArray, rows * columns * sizeof(int)); //保存有效转换数组
changedFlag = 1;
}
memcpy(coinArray, backcoinArray, rows * columns * sizeof(int));//恢复数组
}
if (changedFlag)
{
loopFlag = 1; //有转换设flag
memcpy(coinArray, tempcoinArray, rows * columns * sizeof(int)); //刷新有效转换数组后输出
#if DEBUG_LOG
arrayRestore(coinArray, rows, columns);
outputArray(coinArray, rows, columns);
arrayConvert(coinArray, rows, columns);
#endif
}
}
//列转换
for (j = 0; j < columns; j++)
{
if (columnSum(j) < 0)
{
columnTrans(j);
#if DEBUG_LOG
arrayRestore(coinArray, rows, columns);
outputArray(coinArray, rows, columns);
arrayConvert(coinArray, rows, columns);
#endif
loopFlag = 1;
}
}
columnequalNum = 0;
changedFlag = 0;
for (j = 0; j < columns; j++)
{
//if (0 == columnSum(j)) //仅仅是0和1个数一样的组合
{
columnequalArray[columnequalNum++] = j;
}
}
oldVal = rowabsSum();
if (columnequalNum)
{
for (m = 1; m < (1 << columnequalNum); m++)
{
memcpy(backcoinArray, coinArray, rows * columns * sizeof(int));
for (n = 0; n < columnequalNum; n++)
{
if (m & (1 << n))
{
columnTrans(*(columnequalArray + n));
}
}
newVal = rowabsSum();
if (newVal > oldVal)
{
oldVal = newVal;
memcpy(tempcoinArray, coinArray, rows * columns * sizeof(int));
changedFlag = 1;
}
memcpy(coinArray, backcoinArray, rows * columns * sizeof(int));
}
if (changedFlag)
{
loopFlag = 1;
memcpy(coinArray, tempcoinArray, rows * columns * sizeof(int));
#if DEBUG_LOG
arrayRestore(coinArray, rows, columns);
outputArray(coinArray, rows, columns);
arrayConvert(coinArray, rows, columns);
#endif
}
}
} while (loopFlag);
}
}
void rowTrans(int rowtransNum)
{
int j;
for (j = 0; j < columns; j++)
{
if (*(coinArray + rowtransNum * columns + j) == 1)
{
*(coinArray + rowtransNum * columns + j) -= 2;
}
else
{
*(coinArray + rowtransNum * columns + j) += 2;
}
}
}
void columnTrans(int columntransNum)
{
int i;
for (i = 0; i < rows; i++)
{
if (*(coinArray + i * columns + columntransNum) == 1)
{
*(coinArray + i * columns + columntransNum) -= 2;
}
else
{
*(coinArray + i * columns + columntransNum) += 2;
}
}
}
void onelineTrans(int* tempArr, int tempRow, int tempColumn)
{
int i;
int j;
if (rowandcoluSum() < 0)
{
for (i = 0; i < tempRow; i++)
{
for (j = 0; j < tempColumn; j++)
{
if (1 == *(tempArr + i * tempColumn + j))
{
*(tempArr + i * tempColumn + j) -= 2;
}
else
{
*(tempArr + i * tempColumn + j) += 2;
}
}
}
}
}
int rowSum(int rowsumNum)
{
int sum = 0;
int j;
for (j = 0; j < columns; j++)
{
sum += *(coinArray + rowsumNum * columns + j);
}
return sum;
}
int columnSum(int columnsumNum)
{
int sum = 0;
int i;
for (i = 0; i < rows; i++)
{
sum += *(coinArray + i * columns + columnsumNum);
}
return sum;
}
int rowabsSum(void)
{
int i;
int sum = 0;
for (i = 0; i < rows; i++)
{
sum += abs(rowSum(i));
}
return sum;
}
int columnabsSum(void)
{
int j;
int sum = 0;
for (j = 0; j < columns; j++)
{
sum += abs(columnSum(j));
}
return sum;
}
int rowandcoluSum(void)
{
int i;
int j;
int sum = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < columns; j++)
{
sum += *((coinArray + i * columns) + j);
}
}
return sum;
}
void arrayConvert(int* tempArr, int tempRow, int tempColumn)
{
int i;
int j;
for (i = 0; i < tempRow; i++)
{
for (j = 0; j < tempColumn; j++)
{
if (*((tempArr + i * tempColumn) + j) == 0)
{
*((tempArr + i * tempColumn) + j) -= 1;
}
}
}
}
void arrayRestore(int* tempArr, int tempRow, int tempColumn)
{
int i;
int j;
for (i = 0; i < tempRow; i++)
{
for (j = 0; j < tempColumn; j++)
{
if (*((tempArr + i * tempColumn) + j) == -1)
{
*((tempArr + i * tempColumn) + j) += 1;
}
}
}
}
测试log:
行数 请输入1~100之间的整数:5
用户输入的行数是:5
列数 请输入1~10之间的整数:4
用户输入的列数是:4
输入的数列是:
0 0 0 0
0 0 0 0
0 1 1 0
0 1 0 1
1 0 0 0
head 最多个数为:5
转换后的数列是:
0 1 1 1
0 1 1 1
1 1 1 0
1 1 0 1
1 1 1 1
head 最多个数为:16
G:\little_fish\fish_c_lesson\jeet_c_practise\2019_1119\coinFliping\coinFliping\Debug\coinFliping.exe (进程 8888)已退出,返回代码为: 0。
若要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口...
五.总结:
1.笔误内存动态分配空间不足造成内存溢出。
HEAP CORRUPTION DETECTED: after Normal block (#77) at 0x0014A808.
CRT detected that the application wrote to memory after end of heap buffer.
(Press Retry to debug the application)
Critical error detected c0000374
coinFliping.exe 已触发了一个断点。
程序“[9048] coinFliping.exe”已退出,返回值为 0 (0x0)。

2.数组复制备份时直接复制会造成循环崩溃,需要使用memcpy。
版权声明:本文为JeetLiu原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。