[动态规划] NKOJ 4250 小区划分

问题描述


一条街道的两侧各连续坐落着 N 座单元楼。现在要为这些单元楼划分居民校区。
规则如下:
每个小区只能由同一侧连续的若干座单元楼组成。且两侧都恰有 K 个小区(每个小区至少有一栋楼)。
两侧的小区划分规则应该相同,比如,若左边的房子被分成 {1,2},{3} 这两个小区,那么右边也应该如此。
这样两边合计一共有 K 对小区。
用 ai,bii​​,b​i​​ 表示左右两边每座楼的人口在同侧所有单元楼总人口中所占的百分比,定义一个小区的相对拥挤程度为其人口百分比之和(左边就是对应 aia_ia​i​​ 的和,右边是对应 bib_ib​i​​ 的和)。定义这条街道的总拥挤程度为左右两边 KKK 对小区的相对拥挤程度之差的绝对值之和。

现在,请你求出可能的最大拥挤程度。


输入格式


第一行两个整数 N 和 k。
第二行 N 个实数,第 i 个数为 ai​i​​。
第三行 N 个实数,第 i 个数位 bi​i​​。

输出格式

一个实数,表示这条街道的最大相对拥挤程度,保留到小数点后六位。


样例输入

3 2

0.1 0.75 0.15

0.4 0.3 0.3


样例输出

0.600000


题解:

本题是一道典型的动态规划。

用f[i,j]表示两边的前I座楼中,被分为J段的情况下,最大可能的拥挤程度之差。

转移方程为f[i,j]=MAX {F[l,j-1]+|Px({l+1,...,i})-Py({l+1,...i})|}

其中Px和Py分别表示将两边大楼划分出(L,I]这段作为小区的拥挤程度之和。

再注意一下边界条件即可。


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define maxn 1000
#define maxm 100
using namespace std;
double a[maxn],b[maxn],dp[maxn][maxm];
int n,k;
double gf_abs(double x)
{
	return x>0?x:-1.0*x;
}
void get_ans()
{
	for(int i=1;i<=n;i++)
	{
		dp[i][1]=gf_abs(a[i]-b[i]);
		for(int loop=2;loop<=i&&loop<=k;loop++)
		{
			for(int j=loop-1;j<i;j++)
			{
				dp[i][loop]=max(dp[i][loop],dp[j][loop-1]+gf_abs(a[i]-a[j]-b[i]+b[j]));
			}
		}
	}
}
void init()
{
	for(int i=1;i<=n;i++)
	{
		scanf("%lf",&a[i]);
		a[i]+=a[i-1];
	}
	for(int i=1;i<=n;i++)
	{
		scanf("%lf",&b[i]);
		b[i]+=b[i-1];
	}	
}
void solve()
{
	scanf("%d %d",&n,&k);
	init();
	get_ans();
	printf("%.6lf",dp[n][k]);
}
int main()
{
	solve();
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值