從零開始的算法題生活(四)

引言

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問題還是挺考驗人的,^_^

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章