今天遇到了几道母函数的题,回忆回忆组合数学的知识。。。
hdu 1028
Ignatius and the Princess III
http://acm.hdu.edu.cn/showproblem.php?pid=1028
大意:N=a[1]+a[2]+a[3]+...+a[m]; 求解整数N的拆分方案数
分析:和母函数的砝码故事很像,使用母函数。
#include <iostream>
#include <cstdio>
using namespace std;
const int N=150;
int c1[N],c2[N];
int main()
{
int n;
while(cin>>n){
for(int i=0;i<=n;i++){
c1[i]=1;
c2[i]=0;
}
for(int i=2;i<=n;i++){
for(int j=0;j<=n;j+=i){
for(int k=0;k<=n&&j+k<=n;k++){
c2[j+k]+=c1[k];
}
}
for(int j=0;j<=n;j++){
c1[j]=c2[j];
c2[j]=0;
}
}
printf("%d\n",c1[n]);
}
return 0;
}
hdu 2082
找单词
http://acm.hdu.edu.cn/showproblem.php?pid=2082
转化题意:不同砝码的个数是给定的。求解<=50的组合情况。
没有memset初始化0,WA了两次。哎。。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=55;
int c1[N],c2[N];
int b[30];
int main()
{
//freopen("cin.txt","r",stdin);
int t;
cin>>t;
while(t--){
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
for(int i=1;i<=26;i++) scanf("%d",&b[i]);
for(int i=0;i<=b[1];i++){
c1[i]=1;
c2[i]=0;
}
for(int i=2;i<=26;i++){
int limit= b[i]*i;
for(int j=0;j<=50&&j<=limit;j+=i){
for(int k=0;j+k<=50;k++){
c2[j+k]+=c1[k];
}
}
for(int j=0;j<=50;j++){
c1[j]=c2[j];
c2[j]=0;
}
}
int ans=0;
for(int i=1;i<=50;i++) ans+=c1[i];
printf("%d\n",ans);
}
return 0;
}
POJ 1014 Dividing
http://poj.org/problem?id=1014
大意:输入6个数字,第i个数字表示价值为i的珠宝的个数。问这些珠宝是不是恩能够等价分给两个人。
分析:这题用多重背包也能做。这里用母函数去做。‘
因为数据的原因,如果不优化时要超时的。因为是奇偶性问题,特殊处理每一种珠宝的个数b[i]。一颗珠宝影响价值最大是6,所以如果b[i]>6,奇数设成7,偶数设成6即可。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=15e4+10;
int c1[N],c2[N];
int b[10];
int main()
{
//freopen("cin.txt","r",stdin);
int ca=1;
while(~scanf("%d%d%d%d%d%d",&b[1],&b[2],&b[3],&b[4],&b[5],&b[6])){
int all=0;
for(int i=1;i<=6;i++) {
if(b[i]>=6){
if(b[i]&1) b[i]=7;
else b[i]=6;
}
all+=i*b[i];
}
if(all==0) break;
printf("Collection #%d:\n",ca++);
if(all&1) {
printf("Can't be divided.\n\n");
continue;
}
all=all>>1;
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
for(int i=0;i<=b[1];i++){
c1[i]=1;
}
for(int i=2;i<=6;i++){
int limit=b[i]*i;
for(int j=0;j<=all&&j<=limit;j+=i){
for(int k=0;k<=all;k++){
if(j+k>all) break;
c2[j+k]+=c1[k];
}
}
for(int j=0;j<=all;j++){
c1[j]=c2[j];
c2[j]=0;
}
if(c1[all]) break;
}
if(c1[all]) printf("Can be divided.\n\n");
else printf("Can't be divided.\n\n");
}
return 0;
}