P1281 书的复制

dp例题 or 水题

先说下题意吧,题面给的题意我都看不懂:

\(n\)本书,每本书有一个页数%a_i%。每个人能写连续的几本书,他们写书的速度可以认为是1页1天。求让\(k\)个人抄完这\(n\)本书的最短时间。

PS:\(k\)个人抄书的时间是其中抄的最慢的人用的时间。

dp的状态非常容易想:dp[i][j]表示前\(i\)本书,用\(j\)个人抄的最短时间。

那么显然可以枚举一个小于\(i\)\(j\)来更新状态,这个方程式很水就不讲了。

重点在于输出方案。

得到的最短时间,根据题意,我们要让后面的人尽可能的抄更多的书。

做法很简单,从后面开始递归,枚举出最大的一段满足的区间供给那个人抄,然后剩下的区间就给剩下的人抄。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 505;

int dp[maxn][maxn];
int a[maxn], b[maxn];
int n, m;
void print(int maxv, int pos)
{
    if(pos == 0) return;
    int sum = 0;
    int i;
    for(i = pos; i >= 1; i--)
    {
        sum += a[i];
        if(sum > maxv) break;
    }
    i++;
    print(maxv, i - 1);
    printf("%d %d\n", i, pos);
}
int main()
{
    memset(dp, 0x3f, sizeof dp);
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        b[i] = b[i - 1] + a[i];
    }
    for(int i = 1; i <= n; i++) dp[i][1] = b[i];
    /*
    for(int k = 2; k <= m; k++)
    {
        for(int i = 2; i <= n; i++)
        {
            for(int j = 1; j < i; j++)
            {
                dp[i][k] = std::min(dp[i][k], std::max(dp[j][k - 1], a[i] - a[j]));
            }
        }
    }
    */
    for(int i = 2; i <= n; i++)
    {
        for(int j = 1; j < i; j++)
        {
            for(int k = 2; k <= m; k++)
            {
                dp[i][k] = std::min(dp[i][k], std::max(dp[j][k - 1], b[i] - b[j]));
            }
        }
    }
    //printf("%d\n", dp[n][m]);
    print(dp[n][m], n);
    return 0;
}
posted @ 2018-11-04 20:57  Garen-Wang  阅读(142)  评论(0编辑  收藏  举报