简单描述一下题意:有n个topic需要在长度为L的讲座若干个中讲完,每个topic耗费时间为ti, topic必须按顺序讲否则学生听不懂,这样每次讲座会剩余一些时间,最好在10分钟以内,讲座的不满意指数计算如下:
DI = -c (1<=t<=10)
(t-10)*(t-10) (t>10)
0 (t=0)
t为讲座剩余时间,讲座不能超出时间。要求输出最少要多少个讲座和在相同讲座下最小的DI。
1<=n<=1000 1<=L<=500
题目比较水三重循环也能过,仔细读题后发现最少讲座数是可以根据贪心方法求解的,然后再根据讲座数DP求解最小DI。
dp[i][j] = min(dp[i][j], dp[k][j-1]+DI(cost(k+1, j)))) 0 <= k < i
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #define maxn 1010 5 using namespace std; 6 7 int n, l, c, t[maxn], sum[maxn], cnt = 1, ans, dp[maxn][maxn]; 8 9 int DI(int time) 10 { 11 if(time>l) return 0; 12 else if(time==l) return 0; 13 else if(l-time<=10) return -c; 14 else return ((l-time)-10)*((l-time)-10); 15 } 16 17 void solve() 18 { 19 //贪心求最优解 20 int start = 1; 21 for(int i=1; i<=n; i++){ 22 if((sum[i]-sum[start-1])>l){ 23 start = i; 24 ans++; 25 } 26 } 27 //dp最小DI 28 for(int i=0; i<=ans; i++) dp[0][i] = 0; 29 for(int i=1; i<=n; i++){ 30 for(int j=1; j<=ans; j++){ 31 for(int k=i-1; k>=0; k--){ 32 if((sum[i]-sum[k])<=l) 33 dp[i][j] = min(dp[i][j], dp[k][j-1]+DI(sum[i]-sum[k])); 34 else break; 35 } 36 } 37 } 38 39 } 40 41 void debug() 42 { 43 for(int i=0; i<=n; i++){ 44 for(int j=0; j<=ans; j++){ 45 cout << dp[i][j] << ' '; 46 } 47 cout << endl; 48 } 49 cout << endl; 50 51 } 52 53 int main() 54 { 55 // freopen("in.txt", "r", stdin); 56 // freopen("out.txt", "w", stdout); 57 58 while(scanf("%d", &n)!=EOF && n) 59 { 60 if(cnt!=1) printf(" "); 61 //input 62 scanf("%d%d", &l, &c); 63 sum[0] = 0;ans = 1; 64 memset(dp, 0x7f, sizeof dp); 65 for(int i=1; i<=n; i++){ 66 scanf("%d", &t[i]); 67 sum[i] = sum[i-1]+t[i]; 68 } 69 solve(); 70 //debug(); 71 //output 72 printf("Case %d: ", cnt++); 73 printf("Minimum number of lectures: %d ", ans); 74 printf("Total dissatisfaction index: %d ", dp[n][ans]); 75 } 76 return 0; 77 }