//题意:
//一个整数数组,长度为n,将其分为m份,使得各分的和相等
//比如:{3,4,2,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
//思路:使用多重背包
//首先遍历一次数组arr[n],把数组中最大值maxN和总和sum记录下来
//那么可能的等分为m = sum / maxN
//在这m份中,假设为p份,每份都为sum/m
//一个整数数组,长度为n,将其分为m份,使得各分的和相等
//比如:{3,4,2,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
//思路:使用多重背包
//首先遍历一次数组arr[n],把数组中最大值maxN和总和sum记录下来
//那么可能的等分为m = sum / maxN
//在这m份中,假设为p份,每份都为sum/m
//然后利用多重背包求每份sum/m;
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
#define MSIZ 1000
#define NSIZ 10000
int dp[NSIZ];
int v, n;
int path[NSIZ][MSIZ];
int num[NSIZ];
typedef struct Node_
{
int data;
int index;
}Node;
Node arr[MSIZ];
vector<vector<int>> vec(MSIZ);
int cmp(int a, int b)
{
return a > b;
}
void zeroPacket(int cost, int value, int index, int id)
{
int i = 0;
for (i = v; i >= cost; i--)
{
if (dp[i] < dp[i - cost] + value)
{
dp[i] = max(dp[i], dp[i - cost] + value);
memcpy(path[i], path[i - cost], sizeof(path[i - cost]));
path[i][index] = id;
}
}
}
void completePacket(int cost, int value, int index, int id)
{
int i = 0;
for (i = cost; i <= v; ++i)
{
if (dp[i] < dp[i - cost] + value)
{
dp[i] = max(dp[i], dp[i - cost] + value);
memcpy(path[i], path[i - cost], sizeof(path[i - cost]));
path[i][index] = id;
}
}
}
void multiPacket(int cost, int value, int m,int index, int id)
{
if (m * cost >= v)
{
completePacket(cost, value,index, id);
return;
}
int k = 1;
while(k <= m)
{
zeroPacket(k * cost, k * value,index, id);
m -= k;
k *= 2;
}
if (m)
{
zeroPacket(m * cost, m * value, index, id);
}
}
int main()
{
int t, i, j, p, q, k;
int sum = 0;
int maxN = INT_MIN;
path[0][0] = true;
j = 0;
int row;
while (scanf("%d", &t) != EOF)
{
memset(num, 0, sizeof(num));
memset(dp, 0, sizeof(dp));
memset(path, -1, sizeof(path));
sum = 0;
for (i = 0;i < t; ++i)
{
scanf("%d", &arr[i].data);
arr[i].index = i;
sum += arr[i].data;
if (maxN < arr[i].data)
{
maxN = arr[i].data;
}
}
int m = sum / maxN;
for (p = m; p >= 2; --p)
{
v = sum / p;
q = 0;
for (i = 0;i < p; ++i)
{
vec[i].clear();
}
j = 0;
do
{
memset(dp, 0, sizeof(dp));
for (i = 0;i < t; ++i)
{
if (arr[i].index != -1)
{
multiPacket(arr[i].data, arr[i].data, 1, arr[i].index, q);
}
}
if (dp[v] != v)
{
break;
}
for (i = 0, k = 0;i < t; ++i)
{
if (path[v][arr[i].index] == q)
{
vec[j].push_back(arr[i].data);
arr[i].index = -1;
}
}
++j;
row = j;
}while(++q < p);
if (q == p)
{
for (i = 0;i < row;++i)
{
for (j = 0; j < vec[i].size(); ++j)
{
printf("%d ", vec[i][j]);
}
printf("\n");
}
break;
}
}
if (q != p)
{
for (i = 0;i < t; ++i)
{
printf("%d ", arr[i].data);
}
printf("\n");
}
else
{
printf("\n");
}
}
return 0;
}

本文介绍了一种使用多重背包算法来解决将整数数组等分成若干组的问题。通过遍历数组找到最大值和总和,确定可能的最大等分数,再利用多重背包算法求解每份的组合。
4405

被折叠的 条评论
为什么被折叠?



