UVA - 607 Scheduling Lectures(贪心+记忆化搜索)

题意:

有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;
}

你可能感兴趣的:(uva,607)