[USACO10JAN]乳酪塔Cheese Towers
阿新 • • 發佈:2018-11-25
題目描述
FJ要建一個乳酪塔,高度最大為T。他有N種乳酪(每種乳酪無限個)。第i種乳酪的高度為Hi(一定是5的倍數),價值為Vi。一塊高度Hi>=K的乳酪被稱為大乳酪,一個乳酪如果在它上方有大乳酪(如果有多塊就只算一次),它的高度Hi就會變成原來的4/5.。FJ想讓他的乳酪塔價值和最大。請你求出這個最大值。
輸入格式:
第一行三個數N,T,K,意義如上所述。 接下來n行,每行兩個數V_i,h_i(注意順序)
輸出格式:
乳酪塔的最大價值
(1 <= T <= 1,000).
N (1 <= N <= 100)
(1 <= V_i <= 1,000,000)
H_i (5 <= H_i <= T)
這一題不難看出是揹包問題,因為dp在這一道題無後效性!
而且N和T的值很小,揹包的時間是O(NT),完全承受的了的
可是如果直接從底往上搜,就會很難判斷出上面是否有大乳酪,那我們怎麼辦呢?
既然直接模擬不行,那我們換個方向總行吧!
所以我們直接從上往下找
//dp[i][0]表示第i高度,沒有大乳酪的最大值
//dp[i][0]表示第i高度,有大乳酪的最大值
就可以推出動態方程了
首先是標頭檔案和定義的陣列:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cstdlib> #include<queue> #include<stack> #include<map> #include<cmath> #include<string> #include<set> #include<ctime> using namespace std; inline int read(){ int x=0,f=0;char s=getchar(); while(!isdigit(s))f|=s=='-',s=getchar(); while( isdigit(s))x=(x<<1)+(x<<3)+s-48,s=getchar(); return !f?x:-x; } inline void print(int x){ if(x<0)putchar('-'),x=-x; if(x>9)print(x/10); putchar(x%10+'0'); } const int N=2e2+20; const int T=2e3+20; int n,t,k; struct node{ int v,h; }a[N]; int dp[T][2]; //dp[i][0]表示第i高度,沒有大乳酪的最大值 //dp[i][0]表示第i高度,有大乳酪的最大值
然後是輸入和初始化
dp一開始全部為0,表示不可用,邊界dp[0][0]=0
n=read();t=read();k=read();
for(int i=1;i<=n;i++)a[i].v=read(),a[i].h=read();
memset(dp,-1,sizeof(dp));dp[0][0]=0;
然後是核心的dp
我們可以分3種不同的情況進行討論
1:
當前已經有大乳酪了,就推出dp[ki+a[i].h/5*4][1]
2:
當前無大乳酪,推出dp[ki+a[i].h][0]
3:
當前無大乳酪並且這個就是大乳酪,利用dp[ki][0]推出dp[ki+a[i].h][1]
程式碼:
for(int ki=0;ki<=t;ki++){
for(int i=1;i<=n;i++){
if(ki+a[i].h/5*4<=t&&dp[ki][1]!=-1)
dp[ki+a[i].h/5*4][1]=max(dp[ki+a[i].h/5*4][1],dp[ki][1]+a[i].v);
if(ki+a[i].h <=t&&dp[ki][0]!=-1)
dp[ki+a[i].h ][0]=max(dp[ki+a[i].h ][0],dp[ki][0]+a[i].v);
if(a[i].h>=k &&dp[ki][0]!=-1)
dp[ki+a[i].h ][1]=max(dp[ki+a[i].h ][1],dp[ki][0]+a[i].v);
}
}
以及最後的輸出
int maxx=-1;
for(int i=0;i<=t;i++)maxx=max(maxx,max(dp[i][0],dp[i][1]));
print(maxx);