题目原链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2110
题目分析:
由于要分1/3的资产,所以要先算出总资产为多少,然后判断能否被3整除。
如果不能,说明无法分割资产,也就输出sorry
如果能,那就要找出可以组合成资产的1/3的组合方法数,那就变成了一个排列组合的问题
刚好整除,那就是valSum/3的方案数。物品n种,每种数量m1,m2…mn。属性值为p1,p2,...,pn,求价值和=valSum/3的组合方法数。
利用母函数的知识,具体可以参考我的另一篇博客:
其中有解释了何为母函数,怎么利用母函数来解决排列组合问题。
AC代码:
/*
方案数,母函数:
算总资产,然后除3,除不尽说明不可分
刚好整除,那就是valSum/3的方案数
物品n种,每种数量m1,m2…mn,
属性值为p1,p2,...,pn,求价值和=valSum/3的组合方法数
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAX = 1e4+10;
int a[MAX],b[MAX];
struct Money
{
int p,m;
}money[110];
int main()
{
int n;
while(1)
{
scanf("%d",&n);
if(n==0)
break;
int valSum = 0;
for(int i = 1;i <= n;i++)
{
scanf("%d %d",&money[i].p,&money[i].m);
valSum += money[i].p*money[i].m;
}
if(valSum%3!=0)
{
printf("sorry\n");
continue;
}
valSum /= 3;
// 母函数计算方案数
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
a[0] = 1; // G = 1*G
for(int i = 1;i <= n;i++) // 总共有n种资产
{
for(int j = 0;j <= valSum;j++)
{
// k小于数量,且加上去的价值要少于我们要算的资产(多的没必要算,没用)
for(int k = 0;k<=money[i].m && (j+k*money[i].p)<=valSum;k++)
b[j+k*money[i].p] += a[j];
}
for(int j = 0;j <= valSum;j++)
{
a[j] = b[j]%10000;
b[j] = 0;
}
}
if(a[valSum]>0)
{
printf("%d\n",a[valSum]);
}
else
printf("sorry\n");
}
return 0;
}