[GDOI2014]採集資源,洛谷P3891,狀態與儲存值互換的Dp
阿新 • • 發佈:2018-11-09
正題
題目連結
給出n中苦工,初始有m元錢,第i種苦工要花費a元,之後每天賺b元,求到達T元最少多少天?
首先,每一種苦工可以買多個。
思考,當錢數和天數一定的時候,所擁有的苦工的生產力越高,收益一定越大,因為苦工會賺更多的錢。
那麼dp就有頭緒了,記為第i天,手上有j元錢的最大生產力。
當有一天的(-1表示無法到達),最少i天。
考慮如何轉移。
因為我們不知道i有多大,那麼我們就來構造一個O(能過)演算法。
對於,我們列舉一個k,表示用k元錢去買苦力, 顯然,
f[i+1][j-k+k元錢能買到的苦力的生產力*1天+f[i][j]*1天]=f[i][j]+k元錢能買到的苦力的生產力????
那段文字是可以處理出來的。
就是一個完全揹包。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> using namespace std; int n,m,t; struct node{ int x,y; }s[110]; int f[1010],dp[1010][1010]; int main(){ scanf("%d %d %d",&n,&m,&t); for(int i=1;i<=n;i++) scanf("%d %d",&s[i].x,&s[i].y); memset(f,-1,sizeof(f)); f[0]=0; for(int i=1;i<=n;i++) for(int j=s[i].x;j<=t;j++) f[j]=max(f[j],f[j-s[i].x]+s[i].y); memset(dp,-1,sizeof(dp)); dp[0][m]=0; if(m>=t){ printf("0"); return 0; } int i=0; while(1){ for(int j=0;j<=t;j++) if(dp[i][j]!=-1) for(int k=0;k<=j;k++){ if(f[k]==-1) continue; if(j-k+f[k]+dp[i][j]>=t){ printf("%d\n",i+1); return 0; } dp[i+1][j-k+f[k]+dp[i][j]]=max(dp[i+1][j-k+f[k]+dp[i][j]],dp[i][j]+f[k]); } i++; } }