hdu 1709
就是给定n种质量的砝码 每种质量的砝码只有一个
求出利用这些砝码 不能称出的重量的个数(重量是这些砝码和的范围之内)
如果个数超过0 就把这些质量的值输出
所以利用这些砝码表示重量的时候既可以相加又可以相减
尤其是可以相减!!!!
<span style="font-family:KaiTi_GB2312;font-size:18px;">#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#define eps 1e-8
#define op operator
#define MOD 10009
#define MAXN 10010
#define INF 0x7fffffff
#define MEM(a,x) memset(a,x,sizeof a)
#define ll __int64
using namespace std;
int a[MAXN],b[MAXN];
int c[110];
int ans[110];
int abs(int x,int y)
{
if(x>y)
return x-y;
return y-x;
}
int main()
{
//freopen("ceshi.txt","r",stdin);
int n;
while(scanf("%d",&n)!=EOF)
{
int sum=0;
for(int i=0;i<n;i++)
{
scanf("%d",&c[i]);
sum+=c[i];
}
sort(c,c+n);
MEM(a,0);
MEM(b,0);
a[0]=1;
a[c[0]]=1;
int len=c[0];
for(int i=1;i<n;i++)
{
for(int j=0;j<=len;j++)
{
b[j+c[i]]+=a[j];
b[abs(c[i],j)]+=a[j];
}
// for(int j=0;j<=len;j++)
// {
// if(a[j]!=0&&c[i]>j)
// {
// b[c[i]-j]+=a[j];
// }
// }
// len+=c[i];
for(int j=0;j<=len+c[i];j++)
{
if(b[j]!=0)
{
a[j]=b[j];
b[j]=0;
}
}
len+=c[i];
}
int cnt=0;
for(int i=1;i<=sum;i++)
{
if(a[i]==0)
{
ans[cnt++]=i;
}
}
if(cnt==0)
{
puts("0");
continue;
}
else
{
printf("%d\n",cnt);
for(int i=0;i<cnt;i++)
{
if(i==0)
printf("%d",ans[i]);
else
printf(" %d",ans[i]);
}
puts("");
}
}
return 0;
}
</span>
hdu 2069 Coin Change
题意就是用五种面值的硬币找零 五种面值为50 25 10 5 1
但是有一个限制条件就是所用的硬币数不能超过100
之前只是用一维的来表示 能组成各数值的种类数 现在加了一维 a[i][j]表示用j个硬币表示数值i的种类数
枚举拓展值时 需要根据使用的硬币数来进行修改
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#define eps 1e-8
#define op operator
#define MOD 10009
#define MAXN 100100
#define INF 0x7fffffff
#define MEM(a,x) memset(a,x,sizeof a)
#define ll __int64
using namespace std;
int a[260][110],b[260][110];//a[i][j]表示用j个硬币组成i值的种类数
int cnt[5]={1,5,10,25,50};
int main()
{
//freopen("ceshi.txt","r",stdin);
int n;
while(scanf("%d",&n)!=EOF)
{
MEM(a,0);
MEM(b,0);
for(int i=0;i<=100;i+=cnt[0])
{
a[i][i]=1;
}
for(int i=1;i<=4;i++)//控制硬币类型 即多项式的第几项
{
for(int j=0;j<=n;j++)//枚举已知数值
{
for(int k=0;k+j<=n;k+=cnt[i])//枚举拓展数值
{
for(int l=0;l+k/cnt[i]<=100;l++)
{
b[j+k][l+k/cnt[i]]+=a[j][l];
}
}
}
for(int j=0;j<=n;j++)
for(int k=0;k<=100;k++)
{
a[j][k]=b[j][k];
b[j][k]=0;
}
}
int sum=0;
for(int i=0;i<=100;i++)
sum+=a[n][i];
printf("%d\n",sum);
}
return 0;
}
hdu 2079 选课时间
给定n个学分 k门课 对于同一个学分 所有的课都试做一样的
所以题目类似于给定若干个值以及这些值的个数 问这些值组成n值的方法数有多少
在循环过程中必须遵循的限制是这个值的个数 其次是 如果这时的值大于n就可以不要再继续计算
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#define eps 1e-8
#define op operator
#define MOD 10009
#define MAXN 100100
#define INF 0x7fffffff
#define MEM(a,x) memset(a,x,sizeof a)
#define ll __int64
using namespace std;
int a[400],b[400];
int cour[20],cnt[20];
int main()
{
//freopen("ceshi.txt","r",stdin);
int tc;
scanf("%d",&tc);
while(tc--)
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=0;i<k;i++)
{
scanf("%d%d",&cour[i],&cnt[i]);
}
MEM(a,0); MEM(b,0);
for(int i=0;i<=n&&(i<=cour[0]*cnt[0]);i+=cour[0])
{
a[i]=1;
}
for(int i=1;i<k;i++)
{
for(int j=0;j<=n;j++)
for(int l=0;l<=cnt[i]&&((l*cour[i]+j)<=n);l++)
{
b[j+l*cour[i]]+=a[j];
}
for(int j=0;j<=n;j++)
{
a[j]=b[j];
b[j]=0;
}
}
printf("%d\n",a[n]);
}
return 0;
}
当然也可以只考虑 值的个数的限制(稍微慢一点)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#define eps 1e-8
#define op operator
#define MOD 10009
#define MAXN 100100
#define INF 0x7fffffff
#define MEM(a,x) memset(a,x,sizeof a)
#define ll __int64
using namespace std;
int a[400],b[400];
int cour[20],cnt[20];
int main()
{
//freopen("ceshi.txt","r",stdin);
int tc;
scanf("%d",&tc);
while(tc--)
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=0;i<k;i++)
{
scanf("%d%d",&cour[i],&cnt[i]);
}
MEM(a,0); MEM(b,0);
for(int i=0;(i<=cour[0]*cnt[0]);i+=cour[0])
{
a[i]=1;
}
for(int i=1;i<k;i++)
{
for(int j=0;j<=n;j++)
for(int l=0;l<=cnt[i];l++)
{
b[j+l*cour[i]]+=a[j];
}
for(int j=0;j<=n;j++)
{
a[j]=b[j];
b[j]=0;
}
}
printf("%d\n",a[n]);
}
return 0;
}
hdu 2152 Fruit
要通过组合得到有M个水果的水果拼盘
现在有n种水果 每种水果最多用A个 最少用B个
问有多少种可能
总的来说还是差不多的 主要的是枚举时的起始量以及最后结束的大小
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#define eps 1e-8
#define op operator
#define MOD 10009
#define MAXN 100100
#define INF 0x7fffffff
#define MEM(a,x) memset(a,x,sizeof a)
#define ll __int64
using namespace std;
int a[110],b[110];
int least[110],mx[110];
int main()
{
//freopen("ceshi.txt","r",stdin);
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=0;i<n;i++)
scanf("%d%d",&least[i],&mx[i]);
MEM(a,0); MEM(b,0);
for(int i=least[0];i<=mx[0];i++)
a[i]=1;
for(int i=1;i<n;i++)
{
for(int j=0;j<=m;j++)
for(int k=least[i];k<=mx[i]&&(j+k)<=m;k++)
{
b[j+k]+=a[j];
}
for(int j=0;j<=m;j++)
{
a[j]=b[j];
b[j]=0;
}
}
printf("%d\n",a[m]);
}
return 0;
}
//母函数也做了不少题了 写点感受吧
总的来说 题目类型一般都是给定一些值 以及使用这些值次数的范围 问组成某个数的种类数
最主要的还是那三个嵌套循环 尤其是枚举k的值 在这里容易产生变化
相对来说 这样的题目不会太难 细心 想好枚举的情况即可