引言
hiho一下第145周,其實看到題目有點無奈,居然是dp,好吧,承認自己好久沒做過dp了。
描述
小Hi、小Ho還有被小Hi強拉來的小Z,準備組隊參加一個智力競賽。競賽採用過關制,共計N個關卡。在第i個關卡中,小Hi他們需要獲得Ai點分數才能夠進入下一關。每一關的分數都是獨立計算的,即使在一關當中獲得超過需要的分數,也不會對後面的關卡產生影響。
小Hi他們可以通過答題獲得分數。答對一道題獲得S點分數,答錯一道題獲得T點分數。在所有的N個關卡中,小Hi他們一共有M次答題機會。在每個關卡中,都可以在累計答題次數不超過M的情況下使用任意次的答題機會。
那麼現在問題來了,對於給定的N、M、S、T和A,小Hi他們至少需要答對多少道題目才能夠完成所有的關卡呢?
輸入
每個輸入文件包含多組測試數據,在每個輸入文件的第一行爲一個整數Q,表示測試數據的組數。
每組測試數據的第一行爲四個正整數N、M、S和T,意義如前文所述。
第二行爲N個正整數,分別表示A1~AN。
對於40%的數據,滿足1<=N,M<=100
對於100%的數據,滿足1<=N,M<=1000,1<=Ti<=50
對於100%的數據,滿足1<=Q<=100
輸出
對於每組測試數據,如果小Hi他們能夠順利完成關卡,則輸出一個整數Ans,表示小Hi他們至少需要答對的題目數量,否則輸出No。
樣例輸入
1
2 10 9 1
12 35
樣例輸出
5
##分析
做dp問題,最重要的是推導出其遞推式,在本題中則爲dp[i][j]=min(dp[i][j],dp[i-1][j]+k),k爲作對的題目數,dp[i]爲在第i關做對的題目數,j爲所做的題目數。
代碼如下:
#include<stdio.h>
#include<string.h>
#include<math.h>
#define min(x,y) x>y?y:x
void getQuestions(int N,int M,int S,int T);
void dp(int N,int M,int S,int T,int Ai[]);
int main(void){
int Q;
int N,M,S,T;
int i=0;
scanf("%d",&Q);
while(i<Q){
scanf("%d%d%d%d",&N,&M,&S,&T);
getQuestions(N,M,S,T);
i++;
}
return 0;
}
void getQuestions(int N,int M,int S,int T){
int i;
int array[N];
for(i=0;i<N;i++){
scanf("%d",&array[i]);
}
dp(N,M,S,T,array);
}
void dp(int N,int M,int S,int T,int Ai[]){
int dp[N+1][M+1];
int i;
int j;
int k;
int left=0;
for(i=0;i<N+1;i++){
for(j=0;j<M+1;j++){
if(i==0)
dp[i][j]=0;
else
dp[i][j]=1000;
}
}
for(i=1;i<=N;i++){
int max=(int)ceil(Ai[i-1]/(S+0.0));
for(k=0;k<=max;k++){
int wrong=(int)ceil((Ai[i-1]-k*S+0.0)/T);
wrong=wrong>=0?wrong:0;
for(left=0;left<=M-k-wrong;left++){
dp[i][k+wrong+left]=min(dp[i][k+wrong+left],dp[i-1][left]+k);
}
}
}
int result=1000;
for(j=1;j<=M;j++){
result=min(result,dp[N][j]);
}
if(result>M)
printf("No");
else
printf("%d",result);
}
總結
用時有點久,但是最終還是做出來了,期間也看了一下別人的思路,dp問題還是挺考驗人的,^_^