GYM 100694 A.Did he drop any good loot? (dp)

来源:互联网 发布:mac os x系统怎么安装 编辑:程序博客网 时间:2024/06/06 00:45

Description
n种物品,每种物品有价值p[i]、重量w[i]和加成d[i],d[i]表示如果带上i物品则可以额外多带d[i]单位重量,最多能带m单位重量的物品,所带物品最多有两个物品可以加成,问最多可以带多少价值的物品
Input
第一行两整数n和m分别表示物品数量和所带物品重量上限,之后n行每行三个整数p[i],w[i],d[i]分别表示第i件物品的价值,重量和加成
(1<=n<=1000,1<=m<=500,1<=p[i]<=1e5,1<=w[i]<=100,0<=d[i]<=100)
Output
输出一个值表示所带物品的最大价值
Sample Input
5 10
1 5 3
2 4 0
3 2 2
4 1 4
5 3 1
Sample Output
15
Solution
dp[pos][pre][last]表示到第pos物品还有pre单位重量可以带,而且还有last个物品可以加成,那么每次有两种转移,一种是pre>=w[pos],那么第pos个物品可以拿(pre>=w[pos]),进而有dp[pos][pre][last]=max(dp[pos][pre][last],dfs(pos+1,pre-w[pos],last)+p[pos]),另一种是可以带上此物品的加成(last>0,pre+d[pos]>=w[pos]),那么有dp[pos][pre][last]=max(dp[pos][pre][last],dfs(pos+1,pre+d[pos]-w[pos],last-1)+p[pos]),
由于初始状态不知道要带多少物品和哪些物品的加成,所以先给200的加成上限,等所有物品都考虑完后看pre是否不小于200,如果小于说明多给了那么该状态就不合法,否则合法,故dfs(1,m+200,2)即为答案
Code

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<vector>#include<queue>#include<map>#include<set>#include<ctime>using namespace std;typedef long long ll;#define INF 0x7fffffff#define maxn 10001int n,m;ll p[maxn],w[maxn],d[maxn],dp[10001][901][3];bool vis[10001][901][3];ll dfs(int pos,ll pre,int last){    if(pos==n+1)    {        if(pre>=200)return 0;        return -INF;    }    if(vis[pos][pre][last])return dp[pos][pre][last];    vis[pos][pre][last]=1;    dp[pos][pre][last]=dfs(pos+1,pre,last);    if(pre>=w[pos])dp[pos][pre][last]=max(dp[pos][pre][last],dfs(pos+1,pre-w[pos],last)+p[pos]);    if(last&&(pre+d[pos]>=w[pos]))dp[pos][pre][last]=max(dp[pos][pre][last],dfs(pos+1,pre+d[pos]-w[pos],last-1)+p[pos]);    return dp[pos][pre][last]; }int main(){    while(~scanf("%d%d",&n,&m))    {        for(int i=1;i<=n;i++)scanf("%I64d%I64d%I64d",&p[i],&w[i],&d[i]);        memset(vis,0,sizeof(vis));        printf("%I64d\n",dfs(1,m+200,2));    }     return 0;}
0 0
原创粉丝点击