题意:
有n个主题。每堂课的时间是L。每个主题各要求t1,t2,...tn(1<=ti<=L)。对于每个主题,你要决定要哪堂课教。并且有如下的规则:
1.每个主题必须完整地包含在一堂课里。不能分成两部分教。
2.主题之间的顺序不能调换,即主题i必须在主题i+1之前教。
同时,如果在每堂课的最后如果能留有10分钟以内的时候,那么学生的不满意程序是最小的。不满意程度的计算如下所示:
D=0(如果剩下的时间是0)。
D=-c(如果剩下的时间在10分钟以内)。
D=(t-10)^2(剩下的情况)
思路:
dp[i, j]表示前i节课,覆盖j个知识点的最小不满意度。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <algorithm>
using namespace std;
const int MAXN = 1010;
int dp[MAXN][MAXN];
int a[MAXN], sum[MAXN];
int L, C;
int getvalue(int v)
{
int t = L - v;
if (t == 0)
return 0;
else if (0 < t && t <= 10)
return -C;
else if (t > 10)
return (t - 10) * (t - 10);
}
int main()
{
int n;
int cases = 0;
while (scanf("%d", &n) && n)
{
scanf("%d %d", &L, &C);
sum[0] = 0;
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]), sum[i] = sum[i-1] + a[i];
for (int i = 0; i <= n; ++i)
{
dp[i][0] = 0;
for (int j = 1; j <= n; ++j)
dp[i][j] = INT_MAX;
}
for (int i = 1; dp[i-1][n] == INT_MAX; ++i)
for (int j = i; j <= n && sum[j] <= i * L; ++j)
for (int k = j; k >= i - 1; --k)
if (sum[j] - sum[k] <= L && dp[i-1][k] != INT_MAX)
dp[i][j] = min(dp[i][j], dp[i-1][k] + getvalue(sum[j] - sum[k]));
else if (sum[j] - sum[k] > L)
break;
int i;
for (i = 1; i <= n; ++i)
if (dp[i][n] != INT_MAX)
break;
if (cases)
printf("\n");
printf("Case %d:\n", ++cases);
printf("Minimum number of lectures: %d\n", i);
printf("Total dissatisfaction index: %d\n", dp[i][n]);
}
return 0;
}