Description
Mapping applications often represent the boundaries of countries, cities, etc. as polylines, which are connected sequences of line segments. Since fine details have to be shown when the user zooms into the map, these polylines often contain a very large number of segments. When the user zooms out, however, these fine details are not important and it is wasteful to process and draw the polylines with so many segments. In this problem, we consider a particular polyline simplification algorithm designed to approximate the original polyline with a polyline with fewer segments.
A polyline with n segments is described by n + 1 points p0=(x0,y0),...,pn=(xn,yn)p0=(x0,y0),...,pn=(xn,yn), with the ith line segment being pi−1pi. The polyline can be simplified by removing an interior point pi(1≤i≤n−1)pi(1≤i≤n−1), so that the line segments pi−1pipi−1pi and pipi + 1 are replaced by the line segment pi − 1pi + 1. To select the point to be removed, we examine the area of the triangle formed by pi−1,pi,andpi+1pi−1,pi,andpi+1 (the area is 0 if the three points are colinear), and choose the point pi such that the area of the triangle is smallest. Ties are broken by choosing the point with the lowest index. This can be applied again to the resulting polyline, until the desired number m of line segments is reached.
Consider the example below.
The original polyline is shown at the top. The area of the triangle formed by p2,p3,andp4p2,p3,andp4 is considered (middle), and p3p3 is removed if the area is the smallest among all such triangles. The resulting polyline after p3p3 is removed is shown at the bottom.
Input
The first line of input contains two integers n(2≤n≤200000)n(2≤n≤200000) and m(1≤m<n)m(1≤m<n). The next n + 1 lines specify p0,...,pnp0,...,pn. Each point is given by its x and y coordinates which are integers between −5000 and 5000 inclusive. You may assume that the given points are strictly increasing in lexicographical order. That is, xi<xi+1xi<xi+1 , or xi=xi+1xi=xi+1 and yi<yi+1yi<yi+1 for all 0≤i<n0≤i<n .
Output
Print on the kth line the index of the point removed in the kth step of the algorithm described above (use the index in the original polyline).
Sample Input
10 7 0 0 1 10 2 20 25 17 32 19 33 5 40 10 50 13 65 27 75 22 85 17
Sample Output
1 9 6
Hint
题目大意:给定n+1个点及其组成的n条折线,每相邻的三个点构成一个三角形,每次选择所有三角形面积中最小的,删除其中三个点的中间点(Pi-1,Pi,Pi+1中的Pi)
采用向量叉乘计算面积,具体可以查询向量叉乘的知识,计算方法为
(x1−x0)∗(y2−y0)−(x2−x0)∗(y1−y0)
由于只需要比较面积大小,为了避免浮点运算,可以免去/2操作,
采用set查询面积最小的三角形时,这道题目限制时间比较长,但是如果暴力求解,每次删除点后重新求解所有三角形面积的话,还是可能会超时,因此采用set进行管理。
由于经常要删除坐标点,因此用两个数组left,right进行模拟链表。
代码如下:
#include <set>
#include <cstdio>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define _max 200005
using namespace std;
int p[_max][2],left[_max],right[_max],S[_max],i,n,m,k;
struct node
{
int num,area;
bool operator < (const node b) const
{
if(area==b.area) return num<b.num;
return area<b.area;
}
};
set<node> s;
inline int Area(int x1,int y1,int x2,int y2,int x3,int y3)
{
return abs(x1*y2+x2*y3+x3*y1-x1*y3-x2*y1-x3*y2);
}
int main()
{
struct node temp;
scanf("%d%d",&n,&m);
for(i=0;i<=n;i++) scanf("%d%d",&p[i][0],&p[i][1]);
for(i=1;i<n;i++)
{
left[i]=i-1;
right[i]=i+1;
temp.area=S[i]=Area(p[left[i]][0],p[left[i]][1],p[i][0],p[i][1],p[right[i]][0],p[right[i]][1]);
temp.num=i;
s.insert(temp);
}
right[0]=1;left[n]=n-1;
k=n-m;int j,t=n+1,pos;
set<node>::iterator it;
for(i=1;i<=k;i++)
{
it=s.begin();
pos=(*it).num;
printf("%d\n",pos);
s.erase(it);
right[left[pos]]=right[pos];
left[right[pos]]=left[pos];
if(left[pos]!=0)
{
temp.area=S[left[pos]];
temp.num=left[pos];
it=s.find(temp);
s.erase(it);
S[left[pos]]=Area(p[left[left[pos]]][0],p[left[left[pos]]][1],p[left[pos]][0],p[left[pos]][1],p[right[left[pos]]][0],p[right[left[pos]]][1]);
temp.area=S[left[pos]];
temp.num=left[pos];
s.insert(temp);
}
if(right[pos]!=n)
{
temp.area=S[right[pos]];
temp.num=right[pos];
it=s.find(temp);
s.erase(it);
S[right[pos]]=Area(p[left[right[pos]]][0],p[left[right[pos]]][1],p[right[pos]][0],p[right[pos]][1],p[right[right[pos]]][0],p[right[right[pos]]][1]);
temp.area=S[right[pos]];
temp.num=right[pos];
s.insert(temp);
}
}
return 0;
}