Coins HDU – 2844
题目链接:
https://vjudge.net/problem/HDU-2844
先看看我比这之前整理出来的模板样式:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string.h>
#include <cstring>
#include <algorithm>
#include <string>
#define MAX 100000
using namespace std;
const int maxn = 1e5+10;
int dp[100005];
int m;
int a[102],c[102];
void zero(int a)//01beibao
{
int j;
for(j=m; j>=a; j--)
{
dp[j]=max(dp[j],dp[j-a]+a);
}
}
void com(int a)
{
int j;
for(j=a; j<=m; j++)
{
dp[j]=max(dp[j],dp[j-a]+a);
}
}
void duochong(int a,int c)
{
if(a*c>m)
{
com(a);
}
else
{
int k=1;
while(c>k)
{
c-=k;
zero(a*k);
k=k*2;
}
zero(a*c);
}
}
int main()
{
int n,i,j;
while(~scanf("%d%d",&n,&m))
{
memset(dp,0,sizeof(dp));
if(!n&&!m)
return 0;
for(i=0; i<n; i++)
scanf("%d",&a[i]);
for(i=0; i<n; i++)
scanf("%d",&c[i]);
for(i=0; i<n; i++)
{
duochong(a[i],c[i]);
}
int ans=0;
for(i=1; i<=m; i++)
{
if(dp[i]==i)
ans++;
}
printf("%d\n",ans);
}
return 0;
}
一开始提交的时候一直错:
Status
Runtime Error(ACCESS_VIOLATION)access violation就是运行的时候访问违例的意思
后来就找到啦这位大牛的博客,没想到我看别人博客整理的模板差不多,自信心爆棚,哈哈,错误原因最后也找到啦,就是二进制的时候写的 while(c>k)我给写成 while(c>a);这就很伤。找啦半天错,,,,
然后说一下思路哈,就是用背包来求出在小于m的背包遍历,他的最后dp数组存的数字就是代表当前容量的最大钱数,当这个钱数与自己的标号一致时就代表那些硬币可以正好凑出这些数量的钱具体看代码。
再说一些下面这个人的思路吧,当时一直错的时候找到的,发现基本一致耐,nice,就是对于dp的处理还是有些不同的,背包是基本一致的,他的思路呢就是吧dp{0}预先赋值为1,其余都为零,然后在经过背包遍历之后,如果有的地方变为一啦,就可以确定就是可以凑出这些钱数,
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
using namespace std;
const int maxn=100005;
int a[105],c[105];
int dp[maxn];
int n,m;
void compty(int x)//完全背包。
{
int i;
for(i=x;i<=m;i++)
dp[i]=max(dp[i],dp[i-x]);
}
void beibao_01(int x)//01背包。可以看着次数。
{
int i;
for(i=m;i>=x;i--)
{
dp[i]=max(dp[i],dp[i-x]);
}
}
void shuju(int cons,int n)
{
int k;
if(cons*n>m)//当输入的数据大于总的M时,应该考虑可以加入的次数,就是(转换妫完全背包题),完全背包,可以去好多次,直到不满足条件为止!
compty(cons);
else
{
k=1;
while(k<n)//当然在小于时就必须考虑这依次是否家还是不加,这就考虑的是01背包的问题。
{
beibao_01(cons*k);
n-=k;
k++;
}
beibao_01(cons*n);
}
}
int main()
{
int i,j;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)break;
memset(a,0,sizeof(a));
memset(c,0,sizeof(c));
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<=n;i++)scanf("%d",&c[i]);
memset(dp,0,sizeof(dp));//初始化,
dp[0]=1;
for(i=1;i<=n;i++)
{
shuju(a[i],c[i]);//依次考虑,分别对你每一个数据谈论!!
}
int sum=0;
for(i=1;i<=m;i++)
{
if(dp[i])
sum++;
}
cout<<sum<<endl;
}
return 0;
}
题目意思:
要求你再给出的M范围(1M),分别用给出的钱币,以及所对应的数量。求出看能并凑出的钱数有多少在(1M)之间,包括边界。。
此题一看就应该可以猜到是用DP做,还有就是可以想到利用母函数。但是再看看数据,就可以排除一般DP,还有就是母函数的M值太大,可能会超时,因此这也是不可行的。
因此就看看DP可以完成了吗!!但是若直接DP可能也会数据就太大,因此也就要分开考虑。—:当一组数据的乘积大于M是,和当小于时,这里就分开考虑.
当数据积大于时,你就可以用完全背包(可以无限利用)直到不符合条件。二:就是小于时,当前的价值是加还是不加都有可能产生不同的结果。因此就可以利用01背包(加或者不加)的方法解决。
接着就是看代码:(细看代码)
https://blog.csdn.net/yangyiping525/article/details/16845019?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3.compare&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3.compare
今天的文章Coins HDU – 2844 ,梦幻题目,从迷迷糊糊到渐渐明朗分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/66561.html