NYOJ squares(计算几何+区间覆盖)

2023-12-06 09:32

本文主要是介绍NYOJ squares(计算几何+区间覆盖),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

描述
In this problem, you are given a sequence S1, S2, ..., Sn of squares of different sizes. The sides of the squares are integer numbers. We locate the squares on the positive x-y quarter of the plane, such that their sides make 45 degrees with x and y axes, and one of their vertices are on y=0 line. Let bi be the x coordinates of the bottom vertex of Si. First, put S1 such that its left vertex lies on x=0. Then, put S1, (i > 1) at minimum bi such that
bi > bi-1 and
the interior of Si does not have intersection with the interior of S1...Si-1.
The goal is to find which squares are visible, either entirely or partially, when viewed from above. In the example above, the squares S1, S2, and S4 have this property. More formally, Si is visible from above if it contains a point p, such that no square other than Si intersect the vertical half-line drawn from p upwards.
输入
The input consists of multiple test cases. The first line of each test case is n (1 ≤ n ≤ 50), the number of squares. The second line contains n integers between 1 to 30, where the ith number is the length of the sides of Si. The input is terminated by a line containing a zero number.
输出
For each test case, output a single line containing the index of the visible squares in the input sequence, in ascending order, separated by blank characters.
样例输入
4
3 5 1 4
3
2 1 2
0
样例输出
1 2 4

1 3

 

其实清楚一看就会发现其实每个正方形都对应一条线段,这个线段就是横向的对角线。所以问题就转化成求线段的覆盖问题,看哪些线段被盖住了。求线段覆盖的时候应为题目数据的要求范围很低,直接暴力随便什么的应该都没有问题,但是要注意一点,线段覆盖之前要先排序一下,因为哪根线段先放结果是不一样的。但我们又可以发现边长小的对角线一定在下面,所以考虑的时候应先按照边长的大小排序一下。接着我们再看一条线段是怎么确定的?其实就是左右端点,根据题目给的整数长度的边长,你会发现求出来的是浮点数的一条线段,浮点数是会产生误差的,之后判断的时候会误差,所以这其实需要一个巧妙的转化,就是说我们把正方行边长扩大sqrt(2),这就成为了数学中的相似,对结果是不影响的,仅相当于整个图都扩大了。

设当前的正方形为b, 紧挨着的前一个为f,扩大sqrt(2)倍的左右端点分别为b.l,f.l以及f.r, b.r,   b.len, f.len是原输入数据的正方形的边长大小, 则有等式b.l=f.r-abs(b.len-f.len), b.r=b.l+2*b.len,这是简单几何,细心看一下就会发现,到此,这题应该就差不多了

 

AC代码:

 

 

# include <cstdio>
# include <cmath>
# include <cstdlib>
# include <cstring>
# include <algorithm>
using namespace std;
struct node{int r, l, len ,no;//左右端点,长度及其编号//r, l是扩大sqrt(2)后的左右端点距离,len是原数据长度 
};
node s[60];
int ans[60];
int compare(node a, node b){return a.len<b.len;//边长最小最下面 ,排序一下 
}
int main(){int n, i, j, k, Max_r, Min_l, cnt;while(scanf("%d", &n)!=EOF){if(n==0){break;}for(i=1; i<=n; i++){scanf("%d", &s[i].len);//输入数据 s[i].no=i;}cnt=0;//初始化s[1].l=0;s[1].r=2*s[1].len;Max_r=s[1].r;for(i=2; i<=n; i++){s[i].l=0;for(j=1; j<i; j++){s[i].l=max(s[i].l, s[j].r-abs(s[i].len-s[j].len));//枚举可能在第i个图形前面的正方形,更新Max_r }s[i].r=s[i].l+2*s[i].len;Max_r=max(Max_r, s[i].r);}sort(s+1, s+1+n, compare);//按边长排序一下 for(i=1; i<=n; i++){for(j=1; j<i; j++){if(s[j].l>=s[j].r){continue;}if(s[i].l<=s[j].l&&s[i].r>=s[j].r){s[j].r=s[j].l;}else if(s[i].l<=s[j].l&&s[i].r<=s[j].r&&s[i].r>=s[j].l){s[j].l=s[i].r;}else if(s[i].l>=s[j].l&&s[i].r>=s[j].r&&s[i].l<=s[j].r){s[j].r=s[i].l;}}}for(i=1; i<=n; i++){//满足要求的,记录编号 if(s[i].r>s[i].l){ans[cnt++]=s[i].no;}}sort(ans, ans+cnt);//按编号排序一下,最后再输出 for(i=0; i<=cnt-1; i++){if(i!=cnt-1){printf("%d ", ans[i]);}else{printf("%d\n", ans[i]);}}}return 0;
}

 

 

 

 

 

这篇关于NYOJ squares(计算几何+区间覆盖)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/461345

相关文章

usaco 1.2 Palindromic Squares(进制转化)

考察进制转化 注意一些细节就可以了 直接上代码: /*ID: who jayLANG: C++TASK: palsquare*/#include<stdio.h>int x[20],xlen,y[20],ylen,B;void change(int n){int m;m=n;xlen=0;while(m){x[++xlen]=m%B;m/=B;}m=n*n;ylen=0;whi

uva 10387 Billiard(简单几何)

题意是一个球从矩形的中点出发,告诉你小球与矩形两条边的碰撞次数与小球回到原点的时间,求小球出发时的角度和小球的速度。 简单的几何问题,小球每与竖边碰撞一次,向右扩展一个相同的矩形;每与横边碰撞一次,向上扩展一个相同的矩形。 可以发现,扩展矩形的路径和在当前矩形中的每一段路径相同,当小球回到出发点时,一条直线的路径刚好经过最后一个扩展矩形的中心点。 最后扩展的路径和横边竖边恰好组成一个直

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

poj 1113 凸包+简单几何计算

题意: 给N个平面上的点,现在要在离点外L米处建城墙,使得城墙把所有点都包含进去且城墙的长度最短。 解析: 韬哥出的某次训练赛上A出的第一道计算几何,算是大水题吧。 用convexhull算法把凸包求出来,然后加加减减就A了。 计算见下图: 好久没玩画图了啊好开心。 代码: #include <iostream>#include <cstdio>#inclu

uva 1342 欧拉定理(计算几何模板)

题意: 给几个点,把这几个点用直线连起来,求这些直线把平面分成了几个。 解析: 欧拉定理: 顶点数 + 面数 - 边数= 2。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc

uva 11178 计算集合模板题

题意: 求三角形行三个角三等分点射线交出的内三角形坐标。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <

XTU 1237 计算几何

题面: Magic Triangle Problem Description: Huangriq is a respectful acmer in ACM team of XTU because he brought the best place in regional contest in history of XTU. Huangriq works in a big compa

最大流=最小割=最小点权覆盖集=sum-最大点权独立集

二分图最小点覆盖和最大独立集都可以转化为最大匹配求解。 在这个基础上,把每个点赋予一个非负的权值,这两个问题就转化为:二分图最小点权覆盖和二分图最大点权独立集。   二分图最小点权覆盖     从x或者y集合中选取一些点,使这些点覆盖所有的边,并且选出来的点的权值尽可能小。 建模:     原二分图中的边(u,v)替换为容量为INF的有向边(u,v),设立源点s和汇点t

poj 3304 几何

题目大意:给出n条线段两个端点的坐标,问所有线段投影到一条直线上,如果这些所有投影至少相交于一点就输出Yes!,否则输出No!。 解题思路:如果存在这样的直线,过投影相交点(或投影相交区域中的点)作直线的垂线,该垂线(也是直线)必定与每条线段相交,问题转化为问是否存在一条直线和所有线段相交。 若存在一条直线与所有线段相交,此时该直线必定经过这些线段的某两个端点,所以枚举任意两个端点即可。

POJ 2318 几何 POJ 2398

给出0 , 1 , 2 ... n 个盒子, 和m个点, 统计每个盒子里面的点的个数。 const double eps = 1e-10 ;double add(double x , double y){if(fabs(x+y) < eps*(fabs(x) + fabs(y))) return 0 ;return x + y ;}struct Point{double x , y