• uva 607(DP+贪心)


    简单描述一下题意:有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 }
    View Code
    奔跑吧!少年!趁着你还年轻
  • 相关阅读:
    二分与三分
    NOIP应试技巧
    数论
    并差集
    最短路
    图的遍历

    最小生成树
    树状数组
    线段树
  • 原文地址:https://www.cnblogs.com/shu-xiaohao/p/3369300.html
Copyright © 2020-2023  润新知