题意:
有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个知识点的最小不满意度。
AC代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
int dp[1005][1005] ,t[1005];
bool vis[1005][1005];
int C, L, n;
int DI(int time) {
if(time == 0) {
return 0;
}else if(1 <= time && time <= 10) {
return -C;
}else {
return (time - 10) * (time - 10);
}
}
int solve() {
int sum = 0 ,cnt = 1;
for(int i = 1; i <= n; i++) {
sum += t[i];
if(sum > L) {
sum = t[i];
cnt++;
}
}
return cnt;
}
int dps(int x,int y) {
if(x == 0) {
return y ? INF : 0;
}
if(vis[x][y]) {
return dp[x][y];
}
dp[x][y] = INF;
int sum = 0;
for(int i = y; i > 0; i--) {
sum += t[i];
if(sum > L)
break;
int ans = dps(x-1, i-1);
if(ans != INF) {
dp[x][y] = min(dp[x][y], ans + DI(L - sum));
}
}
vis[x][y] = true;
return dp[x][y];
}
int main() {
int cas = 1;
int flag = 0;
while(scanf("%d",&n) != EOF && n) {
if(flag++) {
printf("\n");
}
scanf("%d%d",&L,&C);
for(int i = 1; i <= n; i++) {
scanf("%d",&t[i]);
}
int cnt = solve();
memset(dp,0,sizeof(dp));
memset(vis,false,sizeof(vis));
printf("Case %d:\n",cas++);
printf("Minimum number of lectures: %d\n",cnt);
printf("Total dissatisfaction index: %d\n",dps(cnt, n));
}
return 0;
}