[DP] [贪心] [CodeVS3162] 抄书问题

来源:互联网 发布:中国公知和精英的溃败 编辑:程序博客网 时间:2024/04/29 23:39

Description 题目描述

现在要把M本有顺序的书分给K个人复制(抄写),每一个人的抄写速度都一样,一本书不允许给两个(或以上)的人抄写,分给每一个人的书,必须是连续的,比如不能把第一、第三、第四本书给同一个人抄写。现在请你设计一种方案,使得复制时间最短。复制时间为抄写页数最多的人用去的时间。

Input 输入

第一行两个整数MK0KM500
第二行M个整数,第i个整数表示第i本书的页数。

Output 输出

K行,每行两个正整数,第i行表示第i个人抄写的书的起始编号和终止编号。K行的起始编号应该从小到大排列,如果有多解,则尽可能让前面的人少抄写。

Sample Input 样例输入

9 3
1 2 3 4 5 6 7 8 9

Sample Output 样例输出

1 5
6 7
8 9

Limits 限制

详见试题
Time Limit : 1s & Memory Limit : 128MB

第一次见到这题是考试的时候
不会啊!!!
什么都没输出,得了10分(rp就这么用光了……)
首先可以dp做
dp[i][j]表示前i页书被j个人抄,抄写最多的页数
dp[i][j]=min(max(dp[k][i1],sum[k+1,i]))
输出贪心思路搞定
上代码

#include <cstdio> #include <climits> #define MAXN 1100 using namespace std; int dp[MAXN][MAXN]; int ans[MAXN][2]; int n,k,m,i,j; int p,q,cnt; int a[MAXN]; int sum[MAXN]; int mymax(int a,int b) {     return a>b?a:b; } int main() {     scanf("%d %d",&n,&k);     for(i=1;i<=n;i++)         for(j=1;j<=k;j++)             dp[i][j]=INT_MAX;     for(int i=1;i<=n;i++)     {         scanf("%d",&a[i]);         sum[i]=sum[i-1]+a[i];         dp[i][1]=sum[i];     }     for(m=2;m<=k;m++)         for(i=1;i<=n;i++)             for(j=1;j<i;j++)             {                 if(dp[i][m]>mymax(dp[j][m-1],sum[i]-sum[j]))                     dp[i][m]=mymax(dp[j][m-1],sum[i]-sum[j]);             }     p=n,q=k;     for(i=n;i>=1;i--)     {         cnt+=a[i];         if(cnt>dp[n][k])         {             ans[q][0]=i+1;             ans[q][1]=p;             p=i;             q--;             cnt=a[i];         }     }     ans[1][0]=1;ans[1][1]=p;     for(int i=1;i<=k;i++)     if (ans[i][0]&&ans[i][1])         printf("%d %d\n",ans[i][0],ans[i][1]);     return 0; } 

再看题,又是求复制时间最短的最大值,有二分的可能
但是抄写页数单调增加时,需要人数单调减少
就有了下面的说贪心不像贪心,说二分不像二分的玩意…….

#include <cstdio>#define MAXM 510using namespace std;int m,k;int a[MAXM];int p[MAXM][MAXM],c[MAXM][MAXM];int ans[MAXM][2];void getans(int pt,int k,int m){    if (k!=1) getans(pt+1,k-1,c[k][m]);    ans[pt][0]=c[k][m]+1;ans[pt][1]=m;}void work(int num,int page){    int t=0,best;    for (int i=page+1;i<=m;i++)    {        t+=a[i];best=t;        if (p[num-1][page]>best) best=p[num-1][page];        if (!p[num][i]||p[num][i]>best)        {            p[num][i]=best;c[num][i]=page;            if (num!=k) work(num+1,i);            if (num==k&&i==m) getans(1,k,m);        }    }}int main(){    scanf("%d %d",&m,&k);    if (!m&&!k) return 0;    for (int i=1;i<=m;i++)        scanf("%d",&a[i]);    work(1,0);    for (int i=k;i>=1;i--)        printf("%d %d\n",ans[i][0],ans[i][1]);    return 0;}

引用学长一句话:
男人,要直面自己的弱点......

0 0