1. 程式人生 > >[GDOI2014]採集資源,洛谷P3891,狀態與儲存值互換的Dp

[GDOI2014]採集資源,洛谷P3891,狀態與儲存值互換的Dp

正題

      題目連結

      給出n中苦工,初始有m元錢,第i種苦工要花費a元,之後每天賺b元,求到達T元最少多少天?

      首先,每一種苦工可以買多個。

      思考,當錢數和天數一定的時候,所擁有的苦工的生產力越高,收益一定越大,因為苦工會賺更多的錢。

      那麼dp就有頭緒了,記f[i][j]為第i天,手上有j元錢的最大生產力。

      當有一天的f[i][k]!=-1(k\in [t,...])(-1表示無法到達),最少i天。

      考慮如何轉移。

      因為我們不知道i有多大,那麼我們就來構造一個O(能過)演算法。

      對於f[i][j],我們列舉一個k,表示用k元錢去買苦力, 顯然,k\in[0,j]

       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++;
	}
}