CSU-2116 Polyline Simplification

本文详细解析了CSU-2116折线简化算法,通过计算并比较三角形面积来逐步减少折线段数量,最终达到指定的段数。使用C++代码实现算法,通过叉积计算三角形面积,利用set和双向链表维护点的顺序和最小面积的三角形。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CSU-2116 Polyline Simplification

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 \(p_0=(x_0,y_0),...,p_n=(x_n,y_n)\), with the ith line segment being pi−1pi. The polyline can be simplified by removing an interior point \(p_i\)(1≤i≤n−1), so that the line segments $p_{i−1} p_i $and \(p_ip_{i+1}\) are replaced by the line segment \(p_{i − 1}p_{i + 1}\). To select the point to be removed, we examine the area of the triangle formed by \(p_{i−1},p_i\),and $ p_{i+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,and p4 is considered (middle), and p3 is removed if the area is the smallest among all such triangles. The resulting polyline after p3 is removed is shown at the bottom.

Input

The first line of input contains two integers n(2≤n≤200000) and m(1≤m<n)m(1≤m<n). The next n + 1 lines specify p0,...,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<x_{i+1}\) , or \(xi=x_{i+1}\) and \(yi<y_{i+1}\) for all 0≤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

题解

题意:给定n+1个点,每个点可以与它左右两个点形成一个三角形,每次删去最小的那个三角形的中间那个点,直到剩下m+1个点,求被删除点的编号。

这是一道模拟题,需要用到叉积(向量积)计算三角形面积
\[ S_{ABC}= \frac{|\overrightarrow{AB} \times \overrightarrow{AC}|}{2} \]
带入三点坐标化简一下即可,由于题目中所给坐标均为整数,所以我们可以存不除2的结果,这样都为整数可以用int存。我们用set维护一下最小三角形的面积,该三角形中间点是第几个点。用数组模拟一下双向链表维护一下这个点左右各是哪个点,删除这个点时更新一下就好了,记得如果该三角形不是第一个或者最后一个三角形的话还要分别更新一下新形成的三角形的面积。

#include<bits/stdc++.h>
#define maxn 200050
using namespace std;
struct point {
    int x, y;
} a[maxn];
int l[maxn], r[maxn];
int area[maxn];
struct node {
    int val, id;
    node(int val = 0, int id = 0): val(val), id(id) {}
    bool operator < (const node &a) const {
        if (val == a.val) return id < a.id;
        else return val < a.val;
    }
};
int calc1(int x) {
    int p1 = l[x], p2 = x, p3 = r[x];
    return abs(a[p1].x * a[p2].y + a[p2].x * a[p3].y + a[p3].x * a[p1].y - a[p1].x * a[p3].y - a[p2].x * a[p1].y - a[p3].x * a[p2].y);
}
set<node> s;
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    int k = n - m;
    for (int i = 0; i <= n; i++) {
        scanf("%d%d", &a[i].x, &a[i].y);
    }
    r[0] = 1;
    l[n] = n - 1;
    for (int i = 1; i < n; i++) {
        l[i] = i - 1; r[i] = i + 1;
        area[i] = calc1(i);
        s.insert(node(area[i], i));
    }
    for (int i = 1; i <= k; i++) {
        set<node>::iterator it = s.begin();
        int now = (*it).id;
        printf("%d\n", now);
        s.erase(it);
        l[r[now]] = l[now];
        r[l[now]] = r[now];
        if (l[now] > 0) {
            it = s.find(node(area[l[now]], l[now]));
            s.erase(it);
            area[l[now]] = calc1(l[now]);
            s.insert(node(area[l[now]], l[now]));
        }
        if (r[now] < n) {
            it = s.find(node(area[r[now]], r[now]));
            s.erase(it);
            area[r[now]] = calc1(r[now]);
            s.insert(node(area[r[now]], r[now]));
        }
    }
    return 0;
}
/**********************************************************************
    Problem: 2116
    User: Artoriax
    Language: C++
    Result: AC
    Time:392 ms
    Memory:15308 kb
**********************************************************************/

转载于:https://www.cnblogs.com/artoriax/p/10350772.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值