MZOJ2007:路灯的改建计划

路灯的改建计划
(light.pas/c/cpp)

【问题描述】
一天晚上,我们信息学竞赛班的SFJ 同学正往校门外走,忽然眼前一片漆黑,于是直
接把眼镜都摔掉了,再也找不到。后来SFJ 同学从学校管理处了解到昨晚路灯突然熄灭是
因为电路不堪重负,导致空气开关跳闸。
SFJ同学仔细了解每盏路灯的耗电量a[i]与照明度z[i],已知共有N 盏电灯,并且
每盏电灯都可能有不同的耗电量与照明度,现在的问题是要把这N盏电灯分为M 组,新分
出的每组灯的耗电量(即是该组所有打开电灯的耗电量之和)不能超过该组的电灯数目的T
倍,在满足这样的前提下使得照明度尽可能的大,最后算出M 组的最大照明度的和。由于
每组耗电量的限制,该组中的某些电灯可能不被使用,但是仍然应该算作该组灯的数目。
特别注意的是电灯按顺序给出,只能把相邻的几盏灯分在一组。
由于计算较为复杂,SFJ 同学经过反复的计算仍然不能确定结果,现在就请你为他编写
一个程序来解决这个问题。
【输入文件】
light.in 文件中共有N+1 行,第一行三个整数分别为N,M,T 接下来的N 行每行两
个整数,分别为a[i]与z[i],所有数据之间以一个空格分开。
【输出文件】
light.out 文件仅包含一个数,即输出M组的最大照明度的和。
【输入样例1】
2 1 2
2 1
3 2
【输出样例1】
2
【输入样例2】
5 2 2
1 1
2 2
3 3
4 4
5 5
【输出样例2】
10
【数据规模】
对于70%的数据,保证有2<=N<=80,1<=M<=35,1<=T,a[i],z[i]<=35;
对于全部的数据,保证有2<=N<=160,1<=M<=50,1<=T,a[i],z[i]<=50。

背包dp:

#include<cstdio>//dp
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=200;
int n,m,t;
int a[maxn],z[maxn];
int f[maxn*50];//耗电量为x时的照明度 
int f2[maxn][maxn];//第i个到第j个的照明度
int ans[maxn][maxn];//前i个分为j个部分的和的最大值 
int main()
{
	//freopen("light.in","r",stdin);
	//freopen("light.out","w",stdout);
	scanf("%d %d %d",&n,&m,&t);
	for(int i=1;i<=n;i++)
	{
		scanf("%d %d",&a[i],&z[i]);
	}
	
	for(int i=1;i<=n;i++)
	{
		memset(f,0,sizeof(f));
		for(int j=i;j<=n;j++)
		{
			for(int k=(n-i+1)*t;k>=a[j];k--)//枚举耗电量
			{
				f[k]= max(f[k],f[k-a[j]]+z[j]);
			}
			for(int k=0;k<=(j-i+1)*t;k++)
			{
				 f2[i][j]=max(f2[i][j],f[k]);
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=min(i,m);j++)
		{
			for(int k=j-1;k<i;k++)
			{
				ans[i][j]=max(ans[i][j],ans[k][j-1]+f2[k+1][i]);
			}
			
		}
	}
	printf("%d\n",ans[n][m]);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值