算法习题45:对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右)某一个元素也加一;;;一个整数数组,长度为n,将其分为m份,使各份的和相等,求m的最大值

.雅虎:
1.对于一个整数矩阵,存 在一种运算,对矩阵中任意元素 加一时,需要其相邻(上下左右)某一个元素也加一,
现给出一正数矩阵,判断 其是 否能够 由一个全零矩阵经过上述运算得到。
2.一个整数 数组,长度为n,将其分为m份,使各份的和相等,求m的最大值
  比如{3,2,4, 3,6 } 可以分成{3,2,4,3,6} m=1; 
  {3,6}{2,4,3} m=2

  {3,3}{2,4}{6} m=3 所以m的最大值为3

----------------------------------------------------------------------

1:这题我我们自己试着模拟一遍,发现有点类似,扫雷,但是还是有差别的。

我想到了两个制约条件:

(1)某个非零元的值一定小于等于它上下左右的和

(2)整个矩阵的和必须是偶数(因为加1就跟着加另一个1,肯定是偶数)

似乎这两个条件就可以了,难道是必要条件???

我想不到从数学上证明,希望有人能给个清晰的答案。


2:这题我们应该逐步分解,

首先是平均分问题,我们可以分成几份呢?当然最多就是每个元素单独出来,所以最多n份;

其次,是不是1--n这么多都可以呢?不是的,必须总和能够整除份数才行

如果现在需要分成m份,而且能够被数组总和整除,那么就可以计算了,

接下来就是一个数组里找出某几个元素和为total/m 的序列了,

这里类似背包算法,需要用到递归

我这里就引用下面这篇博客代码了,写得比我整齐多了。。。

http://blog.csdn.net/peng_weida/article/details/7741888

#include <cstdio>
#include <cstdlib>

#define NUM	8

int maxShares(int a[], int n);

//aux[i]的值表示数组a中第i个元素分在哪个组,值为0表示未分配
//当前处理的组的现有和 + goal的值 = groupsum
int testShares(int a[], int n, int m, int sum, int groupsum, int aux[], int goal, int groupId);

int main()
{
	//int a[] = {2, 6, 4, 1, 3, 9, 7, 5, 8, 10};
	//int a[]={2,2,3,5,6,6};
	int a[]={1,1,2,2,3,4,5,6};

	//打印数组值
	printf("数组的值:");
	for (int i = 0; i < NUM; i++)
		printf(" %d ", a[i]);

	printf("\n可以分配的最大组数为:%d\n", maxShares(a, NUM));

	return 0;
}

int testShares(int a[], int n, int m, int sum, int groupsum, int aux[], int goal, int groupId)
{
	if (goal < 0)
		return 0;

	if (goal == 0)
	{
		groupId++;
		goal = groupsum;

		if (groupId == m+1)
			return 1;
	}

	for (int i = 0; i < n; i++)
	{
		if (aux[i] != 0)
			continue;

		aux[i] = groupId;
		if (testShares(a, n, m, sum, groupsum, aux, goal-a[i], groupId))
			return 1;

		aux[i] = 0;				//a[i]分配失败,将其置为未分配状态
	}

	return 0;
}
int maxShares(int a[], int n)
{
	int sum = 0;
	int *aux = (int *)malloc(sizeof(int) * n);

	for (int i = 0; i < n; i++)
		sum += a[i];

	for (int m = n; m >= 2; m--)
	{
		if (sum%m != 0)
			continue;

		for (int i = 0; i < n; i++)
			aux[i] = 0;

		if (testShares(a, n, m, sum, sum/m, aux, sum/m, 1))
		{
			//打印分组情况
			printf("\n分组情况:");
			for (int i = 0; i < NUM; i++)
				printf(" %d ", aux[i]);

			free(aux);
			aux = NULL;
			return m;
		}
	}

	free(aux);
	aux = NULL;
	return 1;
}



我的思路和上面差不多,不过上面这个方法借助辅助数组aux[]来表示被访问和分配组别这两个信息  这个技巧不错

而我却是用一个数组来记录当前累加的数字,而是否分配过则通过更改原数组值为0来实现

我的思路比较乱。。

#include <iostream>
using namespace std;

void Print(int *ans, int index);
void H(int k, int sum, int n, int *arr, int dst, int *ans, int index);
bool H2(int k, int sum, int n, int *arr, int dst, int *ans, int index, int* m);

int main() {

	int ans[8];

	int index=0;
	int dst;//每组需要达到的和
	int i =0;

	int n = 8;//数组元素个数
	int m = n;

	int total = 24;//这里是数组的总和
	for(m=n;m>0;m--){
		int test[] = {1,1,2,2,3,4,5,6};
		int groupN = m;
		if(total%m == 0)
			dst = total/m;
		else continue;
		if(test[n-1]>dst)
			continue;
		cout<<"分成"<<m<<"组,"<<"每组和为"<<dst<<endl;
		for(i=n-1;i>=0;i--){
			ans[0] = test[i];
			index = 1;
			if(ans[0] == dst){
				Print(ans, index);groupN--;
				continue;
			}
			if(ans[0] > dst)
				continue;
			H2(0, ans[0], i, test, dst, ans, index, &groupN);
		}
		if(groupN != 0)
			cout<<"失败"<<endl;
		else
			cout<<"成功"<<endl;
		cout<<"***************"<<endl;
	}
	return 0;
}

/*
 * k表示当前访问到第几个元素
 * sum表示当前已累加的和
 * arr表示原数组
 * dst我们需要达到的和
 * ans记录答案
 * m 用来表示是否分组成功,每成功一组就减一,直至为0则成功
 */
bool H2(int k, int sum, int n, int *arr, int dst, int *ans, int index, int* m){
	int i = k;
	for(;i<n;i++){
		if(arr[i] == 0)
			continue;
		int temp = sum + arr[i];
		if(temp<dst){
			ans[index++] = arr[i];
			arr[i] = 0;
			if(!H2(i+1, temp, n, arr, dst, ans, index,m))
				return false;
			index--;
			arr[i] = ans[index];

		}
		else if(temp == dst){
			ans[index++] = arr[i];
			arr[i] = 0;
			Print(ans, index);
			(*m)--;
			index--;
			return false;
		}
		else{
			return true;
		}
	}

	return true;
}


void Print(int *ans, int index){
	int i = 0;
	for(i=0;i<index;i++)
		cout<<ans[i]<<" ";
	cout<<endl;
}


我是打印出所有结果

分成4组,每组和为6
6 
5 1 
4 2 
3 1 2 
成功
***************
分成3组,每组和为8
6 1 1 
5 3 
4 2 2 
成功
***************
分成2组,每组和为12
6 1 1 2 2 
5 3 4 
成功
***************
分成1组,每组和为24
6 1 1 2 2 3 4 5 
成功
***************



还是比较喜欢上面他的做法,这种记录方式很清晰

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值