2015编程之美初赛第一场 B 建造金字塔



时间限制:4000ms

单点时限:2000ms

内存限制:256MB

描述

在二次元中,金字塔是一个底边在x轴上的等腰直角三角形。

你是二次元世界的一个建筑承包商。现在有N个建造订单,每个订单有一个收益w,即建造此金字塔可获得w的收益。对每个订单可以选择建造或不建造。

建造一个金字塔的成本是金字塔的面积,如果两个或多个金字塔有重叠面积,则建造这些金字塔时重叠部份仅需建造一次。

建造一组金字塔的总利润是收益总和扣除成本。现给出这些订单,请求出最大利润。

输入

输入数据第一行为一个整数T,表示数据组数。

每组数据第一行为一个整数N,表示订单数目。

接下来N行,每行三个整数x, y, w,表示一个订单。(x, y)表示建造出的金字塔的顶点,w表示收益。

输出

对于每组数据输出一行"Case #X: Y",X表示数据编号(从1开始),Y表示最大利润,四舍五入到小数点后两位。

数据范围

1 ≤ T ≤ 20

0 ≤ w ≤ 107

小数据

1 ≤ N ≤ 20

0 ≤ x, y ≤ 20

大数据

1 ≤ N ≤ 1000

0 ≤ x, y ≤ 1000

样例输入
3
2
2 2 3
6 2 5
3
1 1 1
2 2 3
3 3 5
3
1 1 1
2 2 3
3 3 6
样例输出
Case #1: 1.00
Case #2: 0.00
Case #3: 1.00

2.解题思路:本题利用区间dp解决。本题要求这些订单中的最大收益。首先可以知道,我们只需要关心每个三角形的右边界点即可。这样才能包含一个完整的三角形。因此,对于所有的三角形,用状态(l,r,w)来描述它。

接下来,定义d(j)表示区间[0,j]上收益的最大值。事先我们要统计出最大边界lim,这样j的变化范围就是0≤j≤lim。下面考虑如何寻找状态转移方程。

(1)当j≥x[i].r时,表示第i个三角形完全包括在[0,j]之间,取建造它与不建造它收益的较大者。即d(j)=max{d(j),d(j)+x[i].w};

(2)当不满足(1)时但j≥x[i].l时,我们关注的是x[i].r处的收益最大值,画图后容易知道,收益增加值是建造第i个金字塔的收益w减去多建设的面积,即S(x[i].l,x[i].r)-S(x[i].l,j)。即得到如下状态转移方程:d(x[i].r)=max{d(x[i].r),d(j)+x[i].w-S(x[i].l,x[i].r)+S(x[i].l,x[i].r)};

(3)当前两个均不满足时,状态转移方程其实和(2)类似,即d(x[i].r)=max{d(x[i].r),d(j)+x[i].w-S(x[i].l,x[i].r)};

最后,不要忘记一种特殊情况:只建造第i个金字塔时候的收益,因此最后还要取上述计算出的收益和只建造第i个金字塔收益的较大者。

当所有区间的收益最大值计算完毕后,答案就是他们中的最大值。注意事先要把d(j)都初始化为无穷小,表示没有计算过。

3.代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

double dp[2100];//dp[j]表示[0,j]范围内的最大收益
struct atom{
	int l, r, w;//每个三角形的左边界,右边界,收益
}x[1100];
int n;
int compare(atom k1, atom k2){//按照左边界由小到大排序
	return k1.l<k2.l;
}
double cal(int k){//长度为k的底边的三角形面积
	return k*k / 4.0;
}
double solve()
{
	scanf("%d", &n); int lim = 0;//lim表示最大的右边界
	for (int i = 1; i <= n; i++){
		int k1, k2, k3; scanf("%d%d%d", &k1, &k2, &k3);
		x[i] = atom{ k1 - k2, k1 + k2, k3 }; lim = max(lim, k1 + k2);
	}
	sort(x + 1, x + n + 1, compare);//按照左边界由小大到
	for (int i = 0; i <= lim; i++) dp[i] = -1e18;//初始化为无穷小
	for (int i = 1; i <= n; i++)
	{
		for (int j = lim; j >= 0; j--)
		if (j >= x[i].r) dp[j] = max(dp[j], dp[j] + x[i].w);//当j大于等于右边界时候,取建设i金字塔和不建设的最大值
		else if (j >= x[i].l) dp[x[i].r] = max(dp[x[i].r], dp[j] - cal(x[i].r - x[i].l) + cal(j - x[i].l) + x[i].w);//计算净成本,然后w减去净成本就是多出来的收益
		else dp[x[i].r] = max(dp[x[i].r], dp[j] - cal(x[i].r - x[i].l) + x[i].w);//多出来的收益就是第i个金字塔的收益w减去它的面积
		dp[x[i].r] = max(dp[x[i].r], x[i].w - cal(x[i].r - x[i].l));//最后再取只建造自己时候的较大者
	}
	double ans = 0;
	for (int i = 0; i <= lim; i++) ans = max(ans, dp[i]);//取所有范围中的最大者
	return ans;
}
int main(){
	//freopen("t.txt", "r", stdin);
	int t; scanf("%d", &t);
	for (int i = 1; i <= t; i++){
		printf("Case #%d: %.2lf\n", i, solve());
	}
	return 0;
}
时间: 2024-10-21 21:24:30

2015编程之美初赛第一场 B 建造金字塔的相关文章

2015编程之美初赛第一场 A 彩色的树

时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定一棵n个节点的树,节点编号为1, 2, -, n.树中有n - 1条边,任意两个节点间恰好有一条路径.这是一棵彩色的树,每个节点恰好可以染一种颜色.初始时,所有节点的颜色都为0.现在需要实现两种操作: 1. 改变节点x的颜色为y: 2. 询问整棵树被划分成了多少棵颜色相同的子树.即每棵子树内的节点颜色都相同,而相邻子树的颜色不同. 输入 第一行一个整数T,表示数据组数,以下是T组数据. 每组数据第一行是n,表示树的节

2015编程之美初赛第一场 C 质数相关

 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 两个数a和 b (a<b)被称为质数相关,是指a × p = b,这里p是一个质数.一个集合S被称为质数相关,是指S中存在两个质数相关的数,否则称S为质数无关.如{2, 8, 17}质数无关,但{2, 8, 16}, {3, 6}质数相关.现在给定一个集合S,问S的所有质数无关子集中,最大的子集的大小. 输入 第一行为一个数T,为数据组数.之后每组数据包含两行. 第一行为N,为集合S的大小.第二行为N个整数,表示集

微软2014编程之美初赛第一场——题目2 : 树

[来源] 题目2 : 树 [分析] 依据输入情况建立起树的模型.树的表示是一个表明父亲节点的数组.核心算法有两个: 计算某一节点的深度.用循环实现,一直向上找父亲节点,直到找到根节点.计算循环的次数即为深度. 计算某一节点的全部子节点.用递归实现. 本题在实现上节点的命名从0至N-1,与题目描写叙述不同. [代码] #include <iostream> #include <vector> using namespace std; vector<int> childre

微软2014编程之美初赛第一场——题目3 : 活动中心

[来源] 题目3 : 活动中心 [分析] 本题採用的是三分法. 输入的一组点中找出左右边界.作为起始边界. while(右边界-左边界<精度){ 将左右边界构成的线段均匀分成3段,推断切割点的距离关系,抹去距离大的一段.更新左右边界. } 输出左(右)边界 [代码] #include <iostream> #include <vector> #include <cmath> #include <iomanip> using namespace std;

编程之美初赛第一场--焦距

题目1 : 焦距 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描写叙述 一般来说.我们採用针孔相机模型,也就是觉得它用到的是小孔成像原理. 在相机坐标系下,一般来说,我们用到的单位长度.不是"米"这种国际单位,而是相邻像素的长度.而焦距在相机坐标系中的大小,是在图像处理领域的一个很重要的物理量. 如果我们已经依据相机參数,得到镜头的物理焦距大小(focal length),和相机胶片的宽度(CCD width),以及照片的横向分辨率(image width),

编程之美初赛第一场 树

题目2 : 树 时间限制:4000ms 单点时限:2000ms 内存限制:256MB 描写叙述 有一个N个节点的树.当中点1是根.初始点权值都是0. 一个节点的深度定义为其父节点的深度+1,.特别的.根节点的深度定义为1. 如今须要支持一系列下面操作:给节点u的子树中,深度在l和r之间的节点的权值(这里的深度依旧从整个树的根节点開始计算).都加上一个数delta. 问完毕全部操作后,各节点的权值是多少. 为了降低巨大输出带来的开销.如果完毕全部操作后.各节点的权值是answer[1..N],请你

2014微软编程之美初赛第一场第三题 活动中心

活动中心 时间限制:12000ms 单点时限:6000ms 内存限制:256MB 描写叙述 A市是一个高度规划的城市,可是科技高端发达的地方,居民们也不能忘记运动和锻炼,因此城市规划局在设计A市的时候也要考虑为居民们建造一个活动中心,方便居住在A市的居民们能随时开展运动,锻炼强健的身心. 城市规划局希望活动中心的位置满足下面条件: 1. 到全部居住地的总距离最小. 2. 为了方便活动中心的资源补给和其它器材的维护,活动中心必须建设在A市的主干道上. 为了简化问题.我们将A市摆在二维平面上,城市的

编程之美初赛第一场

题目3 : 活动中心 时间限制:12000ms 单点时限:6000ms 内存限制:256MB 描写叙述 A市是一个高度规划的城市.可是科技高端发达的地方,居民们也不能忘记运动和锻炼,因此城市规划局在设计A市的时候也要考虑为居民们建造一个活动中心.方便居住在A市的居民们能随时开展运动.锻炼强健的身心. 城市规划局希望活动中心的位置满足下面条件: 1. 到全部居住地的总距离最小. 2. 为了方便活动中心的资源补给和其它器材的维护,活动中心必须建设在A市的主干道上. 为了简化问题.我们将A市摆在二维平

2015编程之美初赛第二场扑克牌

一副不含王的扑克牌由52张牌组成,由红桃.黑桃.梅花.方块4组牌组成,每组13张不同的面值.现在给定52张牌中的若干张,请计算将它们排成一列,相邻的牌面值不同的方案数. 牌的表示方法为XY,其中X为面值,为2.3.4.5.6.7.8.9.T.J.Q.K.A中的一个.Y为花色,为S.H.D.C中的一个.如2S.2H.TD等. 输入 第一行为一个整数T,为数据组数. 之后每组数据占一行.这一行首先包含一个整数N,表示给定的牌的张数,接下来N个由空格分隔的字符串,每个字符串长度为2,表示一张牌.每组数