多边形

A histogram is a simple rectilinear polygon whose boundary consists of two chains such that the upper
chain is monotone with respect to the horizontal axis and the lower chain is a horizontal line segment,
called the base segment (See Figure 1).
Figure 1. A histogram and its base segment (v0, v1)
Let P be a histogram specified by a list (v0, v1, . . . , vn−1) of vertices in the counterclockwise order
along the boundary such that its base segment is (v0, v1). An edge ei
is a line segment connecting two
vertices vi and vi+1, where i = 0,1, . . . , n − 1 and vn = v0.
A path inside P is a simple path which does not intersect the exterior of P. The length of the path
is defined as the sum of Euclidean length of the line segments of the path. The distance between two
points p and q of P is the length of the shortest path inside P between p and q. Your task is to find
the distance between v0 and each point of a given set S of points on the boundary of P. A point of
the set S is denoted by p(k, d) which represents a point q on the edge ek such that d is the distance
between vk and q.
In the histogram of Figure 1, the shortest path between v0 and q1 = p(10,2) is a polygonal chain
connecting v0, v14, v12 and q1 in that order, and its length is 8.595242. The shortest path between v0
and q2 = p(1,1) is a segment directly connecting v0 and q2 with length 15.033296.
Given a histogram P with n vertices and a set S of m points on the boundary of P, write a program
to find the distances between v0 and all points of S.
Input
Your program is to read from standard input. The input consists of T test cases. The number of test
cases T is given in the first line of the input. Each test case starts with a line containing an integer,
n (4 ≤ n ≤ 100,000), where n is the number of vertices of a histogram P = (v0, v1, . . . , vn−1). In
the following n lines, each of the n vertices of P is given line by line from v0 to vn−1. Each vertex is
represented by two numbers, which are the x-coordinate and the y-coordinate of the vertex, respectively.
Each coordinate is given as an integer between 0 and 1,000,000, inclusively. Notice that (v0, v1) is the
base segment. The next line contains an integer m (1 ≤ m ≤ 100,000) which is the size of a set S given
as your task. In the following m lines. Each point p(k, d) of S is given line by line, and is represented
by two integers k and d, where 0 ≤ k ≤ n − 1 and 0 ≤ d < the length of edge ek. All points in the set
S are distinct.
Output
Your program is to write to standard output. Print exactly one line for each test case. The line should
contain exactly one real value which is the sum of the distances between v0 and all points of S. Your
output must contain the first digit after the decimal point, rounded off from the second digit. If each
result is within an error range, 0.1, it will be considered correct. The Euclidean distance between two
points p = (x1, y1) and q = (x2, y2) is √
(x2 − x1)
2 + (y2 − y1)
2.
The following shows sample input and output for two test cases.
Sample Input
2
16
0 0
15 0
15 4
13 4
13 6
10 6
10 2
7 2
7 5
6 5
6 7
3 7
3 3
2 3
2 1
0 1
2
10 2
1 1
8
100000 100000
400000 100000
400000 200000
300000 200000
300000 300000
200000 300000
200000 200000
100000 200000
8
1 0
2 0
3 0
4 0
5 0
6 0
7 0
1 50000
Sample Output
23.6
1909658.1

链接:给你一个n边形,他的每条边都平行于x轴或y轴,从最左下角顶点开始,逆时针一次给出n变形上的端点坐标,然后再给你n变形上的m个点,求最左下角的点到这m个点的最短距离之和,距离要求两点连线不能与n变形的边在内部相交。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <queue>
#include <vector>
#define MM(a,b) memset(a,b,sizeof(a));
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
#define CT continue;
#define SC scanf
const int N=1e5+10;
int cas,n,m;

double f[N];
struct Point{
    double x,y;int k,d,flag;
    void read(){
        scanf("%lf%lf",&x,&y);
    }
}p[2*N],c[2*N];

void init(int i,int k,int d)
{
    p[i]=p[k];
    if(p[k].y<p[k+1].y) p[i].y=p[k].y+d;
    if(p[k].y>p[k+1].y) p[i].y=p[k].y-d;
    if(p[k+1].x>p[k].x) p[i].x=p[k].x+d;
    if(p[k+1].x<p[k].x) p[i].x=p[k].x-d;
    p[i].k=k;
    p[i].d=d;
    p[i].flag=1;
}

double dis(Point a)
{
    return sqrt(a.x*a.x+a.y*a.y);
}

Point operator-(Point a,Point b)
{
    return (Point){a.x-b.x,a.y-b.y,0,0,0};
}

double cross(Point a,Point b)
{
    return a.x*b.y-b.x*a.y;
}

bool cmp(Point a,Point b)
{
    if(a.k!=b.k) return a.k>b.k;
    else return a.d>b.d;
}

int main()
{
    SC("%d",&cas);
    while(cas--)
    {
          SC("%d",&n);
          for(int i=0;i<n;i++) {
                p[i].read();
                p[i].k=i;
                p[i].d=0;
                p[i].flag=0;
          }
          SC("%d",&m);
          for(int i=1;i<=m;i++){
             int k,d;
             SC("%d%d",&k,&d);
             init(i+n-1,k,d);
          }
          sort(p+1,p+n+m,cmp);
          double ans=0;
          int cnt=1;
          c[1]=p[0];
          for(int i=1;i<n+m;i++){
              while(cnt>1&&cross(p[i]-c[cnt-1],c[cnt]-c[cnt-1])>=0) cnt--;
              c[++cnt]=p[i];
              f[cnt]=f[cnt-1]+dis(c[cnt]-c[cnt-1]);
              if(p[i].flag) {
                    ans+=f[cnt];
              }
          }
          printf("%.1f\n",ans);
    }
    return 0;
}

  解决:构建一个凸包

posted @ 2016-08-21 21:45  快点说我帅  阅读(282)  评论(0编辑  收藏  举报