【动态规划】复制书稿
Time Limit:1000MS Memory Limit:65536K
Description
有M本书(编号为1,2,…,M),每本书都有一个页数(分别是P1,P2,…,PM)。想将每本都复制一份。将这M本书分给K个抄写员(1<=K<=M<=500),每本书只能分配给一个抄写员进行复制。每个抄写员至少被分配到一本书,而且被分配到的书必须是连续顺序的。复制工作是同时开始进行的,并且每个抄写员复制一页书的速度都是一样的。所以,复制完所有书稿所需时间取决于分配得到最多工作的那个抄写员的复制时间。试找一个最优分配方案,使分配给每一个抄写员的页数的最大值尽可能小。
Input
第一行两个整数M、K;(K<=M<=500)
第二行M个整数,第i个整数表示第i本书的页数。
Output
输出为一个数,即分配给每一个抄写员的页数的最大值
Sample Input
9 3 1 2 3 4 5 6 7 8 9
Sample Output
17
Hint
样例说明:
三个人抄书的位置分别为:
1-5 (15页)
6-7 (13页)
8-9 (17页)
【思路】
第一问动态规划求最小值
套路:
循环 第一层 每个决策状态
(这个就是每个人啊)
第二层 抉择
(每个人可能抄i=1-m本书)
第三层 前一状态抉择
(这个人的上一个人不就最多抄i-1本书)
第二问贪心求方案
既然已经求出了最小值,因为题目要求要前面的人少写;
我们就从后面开始循环;从最后一个人开始从最后选择要写的书;
贪心尽量多写书,所以只要没超过所求的最小值就一直写就可以了;那就保证了最后一个人写的书是尽量最多的;其他的同理。
【学到的】memset最多赋值127啊,我一开始智障的赋值10000000,一直答案都不对是个负数。。。。找了好久才找到这个原因QAQ
也可以赋值0x7f,如果要赋值更大的就直接赋值好了。为了避免大数相加过大 赋值127/3也是可以的。
【代码】
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 using namespace std; 6 int m,k,a[501],f[501][501],d[501]; 7 int print(int,int); 8 int main() 9 { 10 scanf("%d%d",&m,&k);//输入m本书k个人; 11 memset(f,127/3,sizeof(f));//先初始化一个较大值,因为我们要求小值; 12 for(int i=1;i<=m;i++) 13 { 14 scanf("%d",&a[i]);//输入页数 15 d[i]=d[i-1]+a[i];//d为记录前i本书的总页数 16 f[1][i]=d[i];//一个人抄前i本书 17 } 18 for(int i=2;i<=k;i++)//每个阶段是k个人’ 19 { 20 for(int j=1;j<=m;j++)//每个人抄的书1--m 21 { 22 for(int l=1;l<=j-1;l++)//枚举前i-1个人抄的书,最大就是j-1,因为至少要给最后一个人留一本; 23 { 24 if(f[i][j]>max(f[i-1][l],d[j]-d[l])) 25 { 26 f[i][j]=max(f[i-1][l],d[j]-d[l]);//取较小值 27 } 28 29 } 30 } 31 } 32 cout<<f[k][m]<<endl; 33 print(m,k); 34 } 35 int print(int i,int j) 36 { 37 if(j==0)return 0; 38 if(j==1)//当只有1个人时,那就全抄了 39 { 40 cout<<1<<" "<<i<<endl; 41 return 0; 42 } 43 int t=i,x=a[i]; 44 while(x+a[t-1]<=f[k][m])//贪心,从最后一个人开始,从最后一本书开始;只要不超过我们所求的最小值就一直抄就行了 45 { 46 x+=a[t-1];//抄书 47 t--;//抄到第几本 48 } 49 print(t-1,j-1);//第j-1个人抄t-1本 50 cout<<t<<" "<<i<<endl;//最后递归回来一定先输第一个;t是抄到几本了,i是递归开始的初始值; 51 }