0
点赞
收藏
分享

微信扫一扫

【HDU1171】母函数

1.​​题目链接​​。题意就是给你一些物品,这些物品有价值和数量,将他们分成两堆,尽可能的均分(二者之差尽可能的小)。前边我们分析过了,这可以使用背包解决,但是我们使用母函数也是可以解决的,本质上来说二者的区别不是很大,都是再一堆物品中选出一些合适的东西来,都是组合的思想。我们知道,再母函数的代码里面,我们有一层的循环是这样子写的:

for (i = 1; i<n; ++i) 
{
for (j = 0; j <= limit; ++j)
{
for (k = 0; k <= m[i] && j + k * p[i] <= limit; ++k)
{
if (tmp[j + k * p[i]] || ans[j])
{
tmp[j + k * p[i]] = true;
}

}

}

其中第二层循环那个limit是我们所有物品加起来二点最大值,其实就是指数的最大值,既然是这样,我们就修改这里就可以了,修改成最大值的一般即可。然后再寻找答案的时候,我们找距离这个最近的系数。注意这里我们只是要下标。为什么?因为我们知道,我们在做完多项式的乘法之后:a[i]这个东西,意义有很多,不仅仅是第i项的系数,而且x的指数也是i所以,我们又知道,指数就是我们组合出来的物品的价值。所以,疑问解决。代码奉上:

#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX = 1e6 + 10;
#pragma warning(disable:4996)
int ans[MAX], tmp[MAX], n, m[MAX], p[MAX];
void work(int limit) {
int i, j, k;

memset(ans, 0, sizeof(ans));
memset(tmp, 0, sizeof(tmp));

for (i = 0; i <= m[0]; ++i) {
ans[i*p[0]] = true;
}

for (i = 1; i<n; ++i) {
for (j = 0; j <= limit; ++j) {
for (k = 0; k <= m[i] && j + k * p[i] <= limit; ++k) {
if (tmp[j + k * p[i]] || ans[j]) {
tmp[j + k * p[i]] = true;
}
}
}

for (j = 0; j <= limit; ++j) {
ans[j] = tmp[j];
tmp[j] = false;
}
}

}
int main()
{
while (scanf("%d", &n) && n>0)
{
int SUM = 0;
for (int i = 0; i < n; i++)
{
scanf("%d%d", &p[i], &m[i]);
SUM += p[i] * m[i];
}
work(SUM / 2);
for (int i = SUM / 2; i >= 0; i--)
{
if (ans[i])
{
int A = max(SUM - i, i);
int B = min(SUM - i, i);
printf("%d %d\n", A, B);
break;
}
}

}
return 0;
}

 


举报

相关推荐

0 条评论