题意:有一门课,有N个主题需要被这门课覆盖,每个主题ti有一个上课所需时间,第i+1个主题必须在第i个主题被覆盖后才能被覆盖,并且每个主题必须在一节课内被上完,每节课有一个不高兴值,不高兴值的计算已经给出了公式.
给出一节课的长度,求最少需要多少节课,能够覆盖所有主题,如果存在多种方案都能满足最少节数,求出最少的不高兴值和.
思路:因为题目给出了主题递增的覆盖条件,所有首先可以用贪心求出最少需要的节数M,设dp[i][j]为前i节课覆盖j个主题的最小不高兴值.
那么dp[i][j] = min(dp[i][j], dp[i - 1][k] + DI(k + 1, j) | sum(k + 1, j) <= L)这里的DI(i, j)代表第i个主题到第j个主题在一节课里上的不高兴值,sum(i, j )代表第i个主题到第j个主题的所需时间.
注意有多个输入块,每个块的Case number必须从1开始,这里WA了好几次.
#include <cstdio> #include <algorithm> #include <memory.h> using namespace std; const int MAX = 1001; int dp[MAX][MAX]; int t[MAX], sum[MAX]; int n, L, C; int S(int x, int y){ return sum[y] - sum[x - 1]; } int DI(int x, int y){ int t = L - S(x, y); if(t == 0)return 0; else if(t <= 10)return -C; else return (t - 10) * (t - 10); } int main(int argc, char const *argv[]){ int N; scanf("%d", &N); for(int tc = 1; tc <= N; ++tc){ scanf("%d", &n); int caseno = 1; while(n){ scanf("%d%d", &L, &C); for(int i = 1; i <= n; ++i){ scanf("%d", &t[i]); sum[i] = sum[i - 1] + t[i]; } int M = 1, s = 0; memset(dp, 0x6f, sizeof(dp)); for(int i = 1; i <= n; ++i){ s += t[i]; if(s > L){ s = t[i]; ++M; } } dp[0][0] = 0; for(int i = 1; i <= M; ++i){ for(int j = 1; j <= n; ++j) for(int k = j - 1; k >= 0 && S(k + 1, j) <= L; --k){ dp[i][j] = min(dp[i][j], dp[i - 1][k] + DI(k + 1, j)); } } printf("Case %d:\n\nMinimum number of lectures: %d\nTotal dissatisfaction index: %d\n", caseno++, M, dp[M][n]); scanf("%d", &n); if(n){ printf("\n"); } } if(tc != N){ printf("\n"); } } return 0; }
ZOJ 1183 Scheduling Lectures(DP),布布扣,bubuko.com
ZOJ 1183 Scheduling Lectures(DP)
原文:http://blog.csdn.net/zxjcarrot/article/details/22791447