sgu 129 Inheritance 凸包,线段交点,计算几何 难度:2
129. Inheritance
time limit per test: 0.25 sec.
memory limit per test: 4096 KB
The old King decided to divide the Kingdom into parts among his three sons. Each part is a polygonal area. Taking into account the bad temper of the middle son the King gave him a part of Kingdom such that moving straight from any place of this part to any other place of this part he will not cross the boundary.
There are several mineral deposits in the Kingdom. Each mineral deposit looks like a straight line segment. The middle son wants to know what part of mineral deposits is located inside his territory (not including the boundaries).
Input
The first line contains an integer N (3<=N<=400) - the number of vertexes of the polygon boundaring the territory of King's middle son. Each i-th line of the next N lines contains pair of integers xi, yi (0<=xi,yi<=30000) - a position of the i-th vertex (3<=i<=400). The vertexes are given in random order. There are no any three vertexes laying on a straight line. The next line includes the only integer M (2<=M<=1000) - the number of mineral deposits in the Kingdom. Each j-th line of the next M lines contains two pairs of integers aj1, bj1 - point of the beginning and aj2, bj2 - point of the end of the j-th mineral deposit (0<=aj1,bj1,aj2,bj2<=30000, for 1<=j<=M). The numbers in each line are divided by spaces.
Output
Output file should contain M lines. Each j-th line should contain a real number Lj calculated with precision 0.01 - the lehgth of the middle son's part of j-th mineral deposit.
Sample Input
3
1 1
6 1
1 6
4
1 2 1 4
2 2 2 4
4 2 4 4
6 2 6 4
Sample Output
0
2
1
0 思路很简单,就是涉及到了多个计算几何的知识点
1 领地点都是凸包上的点,需要按照凸包排个序,确定了左下点之后按逆时针排个序就行
2 对于线段,完全列举一下凸包的所有边,看有多少交点即可(一定只有<=2个)
3 对于和凸包有交点的线段,如果两个相邻点的中点在凸包内,那么这俩因为本来就是边界了,所以一定这一段在凸包里,如果没有交点,要是线段中点在凸包内也一样
4 如何判断线段交点?...设线段A=P+t1*v(v是方向向量,P是起点),B=Q+t2*w(w向量,Q起点),u=P-Q,则t1=cross(w,u)/cross(v,w),t2=cross(v,u)/cross(v,w),线段交点要满足t1,t2属于[0,1],满足条件后带入即可
5 如何确定点是否在凸包内?设凸包点集为P,(P按凸包已经排好了,)对于所有的线段p[(i+1)%n],p[i] ,因为P构成了凸包,所以只需要都在左侧即可.(转角法缩略版),画个图看看就懂
注意:使用复数的叉积不知道为什么不行?也许是我的姿势不对
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const double eps=1e-8;
int dcmp(double d){
if(fabs(d)<eps)return 0;
return d>0?1:-1;
}
struct pnt{
double x,y;
pnt():x(0),y(0){}
pnt(double tx,double ty):x(tx),y(ty){}
pnt operator -(pnt p2){
pnt newp(x-p2.x,y-p2.y);
return newp;
}
pnt operator +(pnt p2){
pnt newp(x+p2.x,y+p2.y);
return newp;
}
pnt operator *(double d){
pnt newp(x*d,y*d);
return newp;
}
pnt operator /(double d){
pnt newp(x/d,y/d);
return newp;
}
double dis(pnt p2){
return sqrt((x-p2.x)*(x-p2.x)+(y-p2.y)*(y-p2.y));
}
bool operator ==(pnt p2){
if(dcmp(x-p2.x)==0&&dcmp(y-p2.y)==0)return true;
return false;
}
};
pnt p[2000],inset[2000][2],seg[2000][2];
int n,m,len[2000];
double cross(pnt p1,pnt p2){
return p1.x*p2.y-p1.y*p2.x;
}
bool cmpx(pnt p1,pnt p2){
if(p1.x!=p2.x)return p1.x<p2.x;
return p1.y<p2.y;
}
bool cmp(pnt p1,pnt p2){
return cross(p1-p[0],p2-p[0])<0;
} int isPointInConvexPolygon(pnt p1){
for(int i=0;i<n;i++){
pnt A=pnt(p[(i+1)%n].x-p[i].x,p[(i+1)%n].y-p[i].y);
pnt B=pnt(p1.x-p[i].x,p1.y-p[i].y);
int fl=dcmp(cross(A,B));
if(fl>0)return 0;
if(fl==0){
int maxx=max(p[(i+1)%n].x,p[i].x);
int minx=min(p[(i+1)%n].x,p[i].x);
int maxy=max(p[(i+1)%n].y,p[i].y);
int miny=min(p[(i+1)%n].y,p[i].y);
if(minx<=p1.x&&maxx>=p1.x&&miny<=p1.y&&maxy>=p1.y)return -1;
}
}
return 1;
}
void getinsertpoint(){
for(int i=0;i<n;i++){
pnt v=p[(i+1)%n]-p[i];
for(int j=0;j<m;j++){
pnt w=seg[j][1]-seg[j][0];
if(dcmp(cross(v,w))==0)continue;
pnt u=p[i]-seg[j][0];
double t=cross(w,u)/cross(v,w);
double t2=cross(v,u)/cross(v,w);
if(t2+eps>1||t2+eps<0)continue;
if(t<1+eps&&t+eps>0){
pnt newp=p[i]+v*t;
bool fl=true;
for(int k=0;k<len[j];k++){
if(newp==inset[j][k])fl=false;
}
if(fl)inset[j][len[j]++]=newp;
}
}
}
}
void getlength(){
for(int i=0;i<m;i++){
double leng=0;
if(len[i]==2){
pnt mid1=(seg[i][0]+inset[i][0])/2;
int stamid=isPointInConvexPolygon(mid1);
if(stamid==1){
leng+=seg[i][0].dis(inset[i][0]);
}
mid1=(inset[i][0]+inset[i][1])/2;
stamid=isPointInConvexPolygon(mid1);
if(stamid==1){
leng+=inset[i][0].dis(inset[i][1]);
}
mid1=(seg[i][1]+inset[i][1])/2;
stamid=isPointInConvexPolygon(mid1);
if(stamid==1){
leng+=seg[i][1].dis(inset[i][1]);
}
}
else if(len[i]==1){
pnt mid1=(seg[i][0]+inset[i][0])/2;
int stamid=isPointInConvexPolygon(mid1);
if(stamid==1){
leng+=seg[i][0].dis(inset[i][0]);
}
mid1=(seg[i][1]+inset[i][0])/2;
stamid=isPointInConvexPolygon(mid1);
if(stamid==1){
leng+=seg[i][1].dis(inset[i][0]);
}
}
else if(len[i]==0){
pnt mid1=(seg[i][1]+seg[i][0])/2;
int stamid=isPointInConvexPolygon(mid1);
if(stamid==1){
leng+=seg[i][1].dis(seg[i][0]);
}
}
printf("%.2f\n",leng);
}
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%lf%lf",&p[i].x,&p[i].y);
}
scanf("%d",&m);
for(int i=0;i<m;i++){
scanf("%lf%lf%lf%lf",&seg[i][0].x,&seg[i][0].y,&seg[i][1].x,&seg[i][1].y);
}
for(int i=0;i<m;i++){
sort(seg[i],seg[i]+2,cmpx);
}
sort(p,p+n,cmpx);
sort(p+1,p+n,cmp);
getinsertpoint();
for(int i=0;i<m;i++){
sort(inset[i],inset[i]+len[i],cmpx);
}
getlength();
return 0;
}
sgu 129 Inheritance 凸包,线段交点,计算几何 难度:2的更多相关文章
- hdu 2857:Mirror and Light(计算几何,点关于直线的对称点,求两线段交点坐标)
Mirror and Light Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- 谈谈"求线段交点"的几种算法(js实现,完整版)
"求线段交点"是一种非常基础的几何计算, 在很多游戏中都会被使用到. 下面我就现学现卖的把最近才学会的一些"求线段交点"的算法总结一下, 希望对大家有所帮助. ...
- EDU 50 E. Covered Points 利用克莱姆法则计算线段交点
E. Covered Points 利用克莱姆法则计算线段交点.n^2枚举,最后把个数开方,从ans中减去. ans加上每个线段的定点数, 定点数用gcs(△x , △y)+1计算. #include ...
- Inheritance - SGU 129(线段与多边形相交的长度)
题目大意:给一个凸多边形(点不是按顺序给的),然后计算给出的线段在这个凸多边形里面的长度,如果在边界不计算. 分析:WA2..WA3...WA4..WA11...WA的无话可说,总之细节一定考虑清楚, ...
- hdu 1086(计算几何入门题——计算线段交点个数)
链接:http://acm.hdu.edu.cn/showproblem.php?pid=1086 You can Solve a Geometry Problem too Time Limit: 2 ...
- 【计算几何初步-线段相交】【HDU1089】线段交点
You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/3 ...
- Codeforces Gym100543B 计算几何 凸包 线段树 二分/三分 卡常
原文链接https://www.cnblogs.com/zhouzhendong/p/CF-Gym100543B.html 题目传送门 - CF-Gym100543B 题意 给定一个折线图,对于每一条 ...
- SGU 110. Dungeon 计算几何 难度:3
110. Dungeon time limit per test: 0.25 sec. memory limit per test: 4096 KB The mission of space expl ...
- poj 3348 Cows 凸包 求多边形面积 计算几何 难度:0 Source:CCC207
Cows Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 7038 Accepted: 3242 Description ...
随机推荐
- [BZOJ4244]邮戳拉力赛
Description IOI铁路是由N+2个站点构成的直线线路.这条线路的车站从某一端的车站开始顺次标号为0...N+1. 这条路线上行驶的电车分为上行电车和下行电车两种,上行电车沿编号增大方向行驶 ...
- 加法变乘法|2015年蓝桥杯B组题解析第六题-fishers
加法变乘法 我们都知道:1+2+3+ ... + 49 = 1225 现在要求你把其中两个不相邻的加号变成乘号,使得结果为2015 比如: 1+2+3+...+1011+12+...+2728+29+ ...
- The DELETE statement conflicted with the REFERENCE constraint
Page是主表,主键是pageid:UserGroupPage表中的PageID字段是Page表里的数据. https://www.codeproject.com/Questions/677277/I ...
- [微信开发] - 微信支付 JSAPI 形式
微信官方的JSAPI文档 微信官方的JSAPI支付SDK与DEMO下载 查看JSAPI的API可以从这里看 下载了支付DEMO其实有些地方不对的,比如如果做沙盒测试的时候,需要使用getsignkey ...
- C#学习笔记(十七):委托、事件、观察者模式、匿名委托和lambert表达式
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- 如何每日增量加载数据到Hive分区表
如何每日增量加载数据到Hive分区表 hadoop hive shell crontab 加载数据 数据加载到Hive分区表(两个分区,日期(20160316)和小时(10))中 每日加载前一天的日志 ...
- MVC ---- 标准查询运算符
标准查询运算符:定义在System.Linq.Enumerable类中的50多个为IEnumerable<T>准备的扩展方法,这些方法用来 对它操作的集合进行查询筛选. 筛选集合Where ...
- P2865 【[USACO06NOV]路障Roadblocks】(次短路)
传送门 算法Dijkstra要求次短路 那么在不考虑重复走一条边的情况下 肯定是把最短路中的一段改成另一段 至少要换另一条边到路径里所以可以枚举所有不属于最短路的每条边(a,b) 那么dis(1,a) ...
- hihoCoder 1636 Pangu and Stones
hihoCoder 1636 Pangu and Stones 思路:区间dp. 状态:dp[i][j][k]表示i到j区间合并成k堆石子所需的最小花费. 初始状态:dp[i][j][j-i+1]=0 ...
- python通过get方式,post方式发送http请求和接收http响应-urllib urllib2
python通过get方式,post方式发送http请求和接收http响应-- import urllib模块,urllib2模块, httplib模块 http://blog.163.com/xyc ...