6-4 Programming Contest (30分)

Bob will participate in a programming contest. There are altogether n problems in the contest. Unlike in PAT (Programming Ability Test), in a programming contest one can not obtain partial scores. For problem i, Bob will need time[i] to solve it and obtains the corresponding score[i], or he may choose not to solve it at all. Bob will be happy when he obtains a total score no less than happy_score. You are supposed to find the minimum time needed for Bob to be happy. The function need_time must return the minimum time, or -1 if it is impossible for Bob to obtain a score no less than happy_score.

Format of function:

int need_time(const int time[], const int score[], int happy_score, int n);

Here n (1≤n≤ MAXN) is the number of problems; happy_score (1≤ happy_score ≤ MAXS) is the minimum score for Bob to be happy; time[] is the array to store time[i] (1≤time[i]≤100) which is the time to solve problem i; score[] is the array to store score[i] (1≤score[i]≤100) which is the score Bob gets for solving problem i.

Sample program of judge:

#include 

#define MAXN 10
#define MAXS 1000

int need_time(const int time[], const int score[], int happy_score, int n);

int main() {
  int n, i, happy_score;
  int time[MAXN], score[MAXN];
  scanf("%d %d", &n, &happy_score);
  for (i = 0; i < n; ++i)
      scanf("%d", &time[i]);
  for (i = 0; i < n; ++i)
      scanf("%d", &score[i]);
  printf("%d\n", need_time(time, score, happy_score, n));
  return 0;
}

/* Your function will be put here */

Sample Input:

6 121

84 87 78 16 94 38
87 93 50 22 63 28

Sample Output:

125

思路:

题目初看蛮复杂的,想清楚了会发现其实是一道典型的0/1背包问题,可以采用动态规划。
给定了一系列题目,要我们选其中的某些题目做,达到开心值,并花的时间最少。也就是题目要我们从一堆题目里选要做的,这些任务要满足:
1.开心值总和 >= happy_score
2.所花时间总和最少

我们不要从正面考虑问题,换个角度,逆向思维。我们从这一堆题目里选不做的,这些题目要满足:
1.开心值之和<=happy_score
2.所花的时间总和最多

因为一旦不做的题目达到上述两个条件了,剩下的要做的题目自然也就满足要求了。这点想清楚了就会发现题目很简单,而且就是一个0/1背包模型。
happy_score就是背包的空间,题目的开心值就是放入背包的物品的体积,而题目的耗时就是每个物品的价值。最后的耗时就是不做的题目的最大耗时,再总时间作个差就得到要做的题目的最少耗时。

源码:

int max(int a,int b)
{
    return a>b?a:b;
}
int need_time(const int time[], const int score[], int happy_score, int n)
{
    int i;
    int sum=0;
    int sum_time=0;
    int min_score=MAXS;
    for(i=0;i<n;i++)
    {
        sum+=score[i];
        sum_time+=time[i];
        min_score=score[i]<min_score?score[i]:min_score;
    }
    if(sum<happy_score)return -1;//所有题目都做也不能达到开心值

    int dp[sum-happy_score+1][n+1];//dp[x][y]:在剩余x空间的背包放入前y件物品所能获得的最大价值

    for(int i=0;i<=sum-happy_score;i++)
        for(int j=0;j<=n;j++)
        	dp[i][j]=0;
        	
    for(int j=min_score;j<=sum-happy_score;j++)
    {
        for(int i=1;i<=n;i++)
        {
            if(j>=score[i-1])
                //剩余背包空间足够放下第i件物品,则在放与不放中选择价值最大的情况
                dp[j][i]=max(dp[j][i-1],time[i-1]+dp[j-score[i-1]][i-1]);
            else
                //剩余背包空间不足放下第i件物品
                dp[j][i]=dp[j][i-1];
        }
    }

    if(sum_time==dp[sum-happy_score][n])
        return -1;
    else
        return sum_time-dp[sum-happy_score][n];
}

下面是用滚动数组优化过的版本:

int max(int a,int b)
{
    return a>b?a:b;
}
int need_time(const int time[], const int score[], int happy_score, int n)
{
    int i;
    int sum=0;
    int sum_time=0;
    int min_score=MAXS;
    for(i=0;i<n;i++)
    {
        sum+=score[i];
        sum_time+=time[i];
        min_score=score[i]<min_score?score[i]:min_score;
    }
    if(sum<happy_score)return -1;

    int dp[sum-happy_score+1];

    for(int i=0;i<=sum-happy_score;i++)
    {
        dp[i]=0;
    }

    int v=sum-happy_score;
	for(int i=1;i<=n;i++)
	{
		for(int k=v;k>=score[i-1];k--)
		{
			dp[k]=max(dp[k],dp[k-score[i-1]]+time[i-1]);
		}
	}
	
    if(sum_time==dp[v])
        return -1;
    else
        return sum_time-dp[v];
}

你可能感兴趣的:(PTA作业题集,算法,动态规划)