题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2159
题目里面有两个限制条件,忍耐度和杀怪数量,所以可以用一个二维数组dp[i][j]来表示在消耗忍耐度i,并且杀怪数量为j时可以得到的最大经验,也可以用三维数组,但是因为每次的答案值依赖前一次的值,所以可以省略一维直接用二维数组。
第一次做这种类型没想到用二维数组,开了两个一维数组做,现在有点觉得这个维数是不是就是限制条件的数量,我们用每一维的数组下标来表示每一种限制条件,那以后如果遇到三个限制条件,多个限制条件,那么是不是应该就是开多维数组来进行计算,感觉又更懂了那么一点点。
我看博客之后的代码和第一次写的代码:
看了博客之后:
#include<iostream> #include<cstring> #include<algorithm> #include<queue> #include<map> #include<stack> #include<cmath> #include<vector> #include<set> #include<cstdio> #include<string> #include<deque> using namespace std; typedef long long LL; #define eps 1e-8 #define INF 0x3f3f3f3f #define maxn 105 /*struct point{ int u,w; }; bool operator <(const point &s1,const point &s2) { if(s1.w!=s2.w) return s1.w>s2.w; else return s1.u>s2.u; }*/ int dp[maxn][maxn];//dp[i][j]表示忍耐度消耗i,杀死怪物数量为j时可以获得的最大经验 int v[maxn],w[maxn]; int n,m,k,t,s; int main() { while(scanf("%d%d%d%d",&n,&m,&k,&s)!=EOF) { for(int i=1;i<=k;i++) scanf("%d%d",&v[i],&w[i]); memset(dp,0,sizeof(dp)); int ans=-1; for(int i=1;i<=m;i++)//忍耐度,第一个限制条件,这三个循环可以互换位置,但是因为题目要我们求 { //最后剩余的最大忍耐值,所以忍耐度放在第一层循环应该更快一点,可以跳出 for(int j=1;j<=s;j++)//杀怪数量,第二个限制条件 { for(int e=1;e<=k;e++)//怪物种类 { if(i>=w[e]) dp[i][j]=max(dp[i][j],dp[i-w[e]][j-1]+v[e]); } if(dp[i][j]>=n) { ans=i; break; } } if(ans!=-1) break; } if(ans!=-1) printf("%d\n",m-ans); else printf("%d\n",ans); } return 0; }
开了两个一维数组的代码(经过讨论,下面代码是错的,但是偏偏过了,所以应该是后台数据有问题):
#include<iostream> #include<cstring> #include<algorithm> #include<queue> #include<map> #include<stack> #include<cmath> #include<vector> #include<set> #include<cstdio> #include<string> #include<deque> using namespace std; typedef long long LL; #define eps 1e-8 #define INF 0x3f3f3f3f #define maxn 105 /*struct point{ int u,w; }; bool operator <(const point &s1,const point &s2) { if(s1.w!=s2.w) return s1.w>s2.w; else return s1.u>s2.u; }*/ int n,m,k,s,t; int v[maxn],w[maxn],dp[maxn],num[maxn]; int main() { while(scanf("%d%d%d%d",&n,&m,&k,&s)!=EOF) { for(int i=1;i<=k;i++) scanf("%d%d",&v[i],&w[i]); memset(dp,0,sizeof(dp));//dp[i]表示消耗忍耐度i时可以得到的最大经验值 memset(num,0,sizeof(num));//记录杀怪数量,两个数组同步 for(int i=1;i<=k;i++) { for(int j=w[i];j<=m;j++) { if(num[j-w[i]]+1<=s&&(dp[j]<dp[j-w[i]]+v[i]||dp[j]==dp[j-w[i]]+v[i]&&num[j]>num[j-w[i]]+1)) {//经验值放在第一位,然后杀怪数量第二位,但是前提是不能超出s dp[j]=dp[j-w[i]]+v[i]; num[j]=num[j-w[i]]+1; } } } int ans=-1; for(int i=1;i<=m;i++)//找满足条件并且消耗最小忍耐度的结果 { if(dp[i]>=n) { ans=m-i; break; } } printf("%d\n",ans); } return 0; }