-
[1413] Weight
- 时间限制: 1000 ms 内存限制: 65535 K
- 问题描述
-
有n个砝码,每个砝码都有各自的重量。
那么这些砝码一共能称出哪些重量。
- 输入
-
输入一个正整数 n (1 <= n <= 100)表示一共有 n 个砝码。
接下来一行有n个正整数,每个正整数表示该砝码的重量,其重量不会超过100。 - 输出
-
从小到大输出所有可能的情况。
对于每行,包含两个数,前面一个数是能称出的重量,后面一个数是能称出该重量的不同情况的数量(就算重量相等的砝码也被视为不同的砝码)。
其数量要对100000007求余。 - 样例输入
-
4 1 2 3 4
- 样例输出
-
1 1 2 1 3 2 4 2 5 2 6 2 7 2 8 1 9 1 10 1
- 提示
-
无
- 来源
-
Hungar
思路 :很明显是母函数
#include<stdio.h>
#include<string.h>
int num[111],val[111];
int c1[10000+100],c2[10000+100];
#define mod 100000007;
int main()
{
int n,i,j,k,sum;
while(scanf("%d",&n)!=EOF)
{
sum=0;
memset(num,0,sizeof(num));
for(i=1;i<=n;i++)
{
scanf("%d",&val[i]);
num[val[i]]=1;
sum+=val[i];
}
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
for(j=0;j<=val[1]*num[val[1]];j+=val[1])//限制了每种的个数 最多为 num[val[i]]*val[i] 由于本题都是1 可以去掉不写
/*如 质量为1 的砝码有4个 则母函数第一个式子为为 1+x^1+x^2+x^3+x^4*/
c1[j]=1;
for(i=2;i<=n;i++)
{
for(j=0;j<=sum;j++)//指向上一次已经计算过的式子的项
for(k=0;k+j<=sum&&k<=num[val[i]]*val[i];k+=val[i])//限制了每种的个数就要这样写了
{//k指向当前要成的式子的项
c2[k+j]+=c1[j]%mod;
c2[k+j]%=mod;
}
for(k=0;k<=sum;k++)
{
c1[k]=c2[k]%mod;
c2[k]=0;
}
}
for(i=1;i<=sum;i++)
if(c1[i])
printf("%d %d\n",i,c1[i]);
}
return 0;
}
下面的是官方的解题报告 :
A.Weight
由题可知,砝码数量不超过100,每个砝码的重量不超过100,那么总重不会超过10000.
我们可以申请一个数组a,a[i]表示组成重量i的数量。
那么对于每个砝码,我们都对a数组遍历一遍,
当a[i]是真值时,那么a[i+当前砝码的重量]+=a[i](不要忘了求余),
所以要从尾部开始遍历,不能从头部开始遍历。
但是我们可以剪枝一下,每次都是从10000开始遍历到0有点漫长。
所以我们可以定义一个数all = 0;
all存的是当前砝码以及该砝码之前的所有砝码的总和重量,所以每次只要从all开始遍历到0即可。
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define mod 100000007
#define N 110
#define M 10005
int a[M];
int main()
{
int n;
while (~scanf("%d", &n))
{
int all = 0;
memset(a, 0, sizeof(a));
a[0] = 1;
for (int i = 0; i < n; i++)
{
int x;
scanf("%d", &x);
all += x;
for (int j = all; j >= 0; j--)
{
if (a[j]) a[j + x] = (a[j + x] + a[j]) % mod;
}
}
for (int i = 1; i <= all; i++)
{
if (a[i]) printf("%d %d\n", i, a[i]);
}
}
return 0;
}