luogu1281:书的复制:区间DP+贪心

93 篇文章 0 订阅
26 篇文章 0 订阅

最近在复习DP,从最傻的题目开始敲,再次发现自己的失意症;去luogu重刷的时候,很惊奇低发现,原来最后一篇题解还是自己写(chao)的,当时还非常嘚瑟写了一个二分的一题多解,66666


题目连接:

题目大意:(本题有2问)

1 有n本连续的书,需要分给m个人,同时抄写;

2 要求每个人都需要抄连续编号的书,总时间最少;

3 第一问: 其实就是“分到最多书的人,页数尽可能少”

4 第二问:要求前面的人尽可能少抄,输出每个人的得书情况;


解题思路:

1 DP部分:问什么设什么:f[i][j]表示:前i本书分给前j个人,抄写的时间最短;

2 枚举最后一个人能分到k本书;

3 转移方程:f[i][j]=min(f[i][j],max(f[i-k][j-1],s[i]-s[i-k-1]));//别怂,下面是详解↓

3.1 转移方程拆分1: max(f[i-k][j-1],s[i]-s[i-k-1]) 

3.1.1 当前书一共有i本,最后一个人(第j个人)抄k本,所以前(j-1)个人,抄(i-k)本,前面(j-1)个人抄(i-k)本书的时间是f[i-k][j-1];最后一个人抄书的时间是:s[i]-s[i-k-1],两者取最大值(因为是同时抄的);

3.2 转移方程拆分2:min(f[i][j],xxx);//枚举求最小值,能看懂吧,

3.3 到这里,DP部分结束了,能算出最少的用时,但是不知道每个人具体 能分派到哪一段的书;

4 贪心部分:因为题目说:“前面的人尽可能少抄”,因为每个人需要抄的最大值,已经求出来了,所以从后往前扫一遍,就可以了。


上代码:

#include<bits/stdc++.h>
using namespace std;

int n,m,t=0;
int a[510],s[510];
int b[510],f[510][510];

void dp()
{
	for(int j=2;j<=m;j++)//第j个人 
	{
		for(int i=j;i<=n;i++)//前i本书 
		{
			for(int k=j;k<=i;k++)//最后一个人拿后k本 
			{
				int ans=0;
				ans=max(f[k-1][j-1],s[i]-s[k-1]);//详解请看:3.1 
				f[i][j]=min(f[i][j],ans);//3.2
			}
		}
	}
}
void pr()
{
	b[++t]=n;//b[t]:第t个人抄的最后一本书的编号 
	int su=0;
	for(int i=n;i>=1;i--)//从后往前扫一遍 
	{
		if(su+a[i]>f[n][m])
		{
			b[++t]=i;
			su=a[i];
		}
		else su+=a[i];
	}
	printf("%d %d\n",1,b[t]);//第一个人要单独输出
	 
	for(int i=t;i>1;i--) printf("%d %d\n",b[i]+1,b[i-1]);
}

int main()
{
	s[0]=0;
	memset(f,63,sizeof(f));
	
	scanf("%d %d",&n,&m);//n本书分给m个人;
	if(n==0) return 0;
	
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		f[i][1]=s[i]=s[i-1]+a[i];
	}
	
	dp();//DP部分 

	pr();//利用贪心输出 
	
	
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值