题目链接:点击打开链接
题目大意:略。
解题思路:完全背包。
AC 代码
#include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof a); using namespace std; typedef long long ll; const int maxn=10000+10; int dp1[maxn],dp2[maxn]; int weight[maxn]; int main() { int n,m; while(~scanf("%d%d",&n,&m)) { for(int i=0;i<n;i++) scanf("%d",&weight[i]); for(int i=0;i<maxn;i++) { dp1[i]=maxn; dp2[i]=-maxn; } dp1[0]=dp2[0]=0; for(int i=0;i<n;i++) { for(int j=weight[i];j<=m;j++) { // PS1:加判断状态是否可转移(dp[m]一定代表正好背包放满的状态的值):因为for_j循环体内,每一种可能,都要经过判断,当前状态是否可转移,若可以,则调用max,否则跳过当前状态,进入下一种状态。 // PS2:不加判断状态是否可转移(dp[m]不一定代表正好背包放满的状态的值):因为 j 代表每一种可能性,并不代表一个确定的使用空间的量,所以 dp[m] 到最后可能是一个虚值,但是如果dp初始化时,是个负大值(注意:这个负数要足够大,使虚值到达不了正数,否则会与真值混乱),dp[m] 最终且大于0,则该 dp[m] 是真实值。 if(j==weight[i] || dp1[j-weight[i]]!=maxn) dp1[j]=min(dp1[j],dp1[j-weight[i]]+1); if(j==weight[i] || dp2[j-weight[i]]!=-maxn) dp2[j]=max(dp2[j],dp2[j-weight[i]]+1); } } printf(dp1[m]==maxn?"-1":"%d",dp1[m]); printf(dp2[m]<=0?" -1\n":" %d\n",dp2[m]); // 临界点是 dp2[m]>0 而不是 dp2[m]==-maxn // if(dp2[m]>0) // 因为最大值有符合的值,那么最小值肯定有,大不了最小值==最大值 // printf("%d %d\n",dp1[m],dp2[m]); // else // 最大值都小于等于0,那么最小值肯定也没有 // printf("-1 -1\n"); } return 0; }