PS:真心后悔没有把大白带回家
数组可以重复利用,i是没必要的,否则会MLE
hdu 2844 Coins
题意:和大白上差不多,a是数值,c是数的个数,问从这些数中选出一些数,能形成多少个m以内(包括m)的结果
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[110],c[110];
int dp[100010]; //dp[i][j]为钱为j时剩下的第i种硬币的数量
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF&&n&&m)
{
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
for(int i=1;i<=n;++i)
scanf("%d",&c[i]);
memset(dp,-1,sizeof(dp));
dp[0]=0;
for(int i=1;i<=n;++i)
for(int j=0;j<=m;++j)
{
if(dp[j]>=0) // !-1说明前i-1种硬币加和能得到j,因此第i种硬币不需要消耗
dp[j]=c[i];
else if(j<a[i]||dp[j-a[i]]<=0) //第i种硬币面值太大,或者太小(前i种硬币无法凑到j-a[i]或者是硬笔数用完了,自然就不可能凑到j)
dp[j]=-1;
else
dp[j]=dp[j-a[i]]-1;
}
int ans=0;
for(int j=1;j<=m;++j)
for(int i=1;i<=n;++i)
{
if(dp[j]>=0)
{
++ans;
break;
}
}
printf("%d\n",ans);
}
}
我们学校已经毕业的巨巨的题解,感觉这个更好,果断放弃自己的!
#include <cstdio>
#include <cstring>
int const MAXM = 1e5 + 5;
int const MAXN = 1e2 + 5;
bool dp[MAXM];
int cnt[MAXM];
int a[MAXN], c[MAXN];
int main()
{
int n, m;
while(scanf("%d %d", &n, &m) != EOF && (n + m))
{
memset(dp, false, sizeof(dp));
for(int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
for(int i = 1; i <= n; i ++)
scanf("%d", &c[i]);
dp[0] = true;
int ans = 0;
for(int i = 1; i <= n; i ++)
{
memset(cnt, 0, sizeof(cnt));
for(int s = a[i]; s <= m; s ++)
{
if(!dp[s] && dp[s - a[i]] && cnt[s - a[i]] < c[i])
{
dp[s] = true;
ans ++;
cnt[s] = cnt[s - a[i]] + 1;
}
}
}
printf("%d\n", ans);
}
}
hdu 1059 dividing
题意:总共有六种收藏品,给出每种的个数,问是否能把它们分成价值相等的两份
思路:转化成是否能凑出价值和的一半
120000*20000*6 普通的多重背包做会T 于是就和上面一样啦
坑点:样例之间要空一行!!!!!怪我没有认真审题!
还因为忘了用continue,以及数组开小了,wawawa
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
//6*20000
const int maxv=120010;
//int dp[maxv];
bool dp[maxv];
int v[10],c[10];
int cnt[maxv]; //cnt一开始开成6 开小了!
int main()
{
int kase=0;
while(scanf("%d%d%d%d%d%d",&c[1],&c[2],&c[3],&c[4],&c[5],&c[6])!=EOF)
{
if(!c[1]&&!c[2]&&!c[3]&&!c[4]&&!c[5]&&!c[6])
break;
int sum=0;
for(int i=1;i<=6;++i)
{
v[i]=i;
sum+=v[i]*c[i];
}
if(sum%2)
{
printf("Collection #%d:\n",++kase);
printf("Can't be divided.\n\n");
continue; //忘记continue wa 了一发
}
memset(dp,false,sizeof(dp));
dp[0]=true;
int ans=0;
for(int i=1;i<=6;++i)
{
memset(cnt,0,sizeof(cnt));
for(int j=v[i];j<=sum/2;++j)
{
if(!dp[j]&&dp[j-v[i]]&&cnt[j-v[i]]<c[i])
{
dp[j]=true;
cnt[j]=cnt[j-v[i]]+1;
ans=max(ans,j);
}
}
}
printf("Collection #%d:\n",++kase);
if(ans==sum/2)
printf("Can be divided.\n\n");
else
printf("Can't be divided.\n\n");
}
return 0;
}