路灯的改建计划
(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;
}