Polyline Simplification

本文介绍了一种基于三角形面积的点删除算法,通过维护每个点的三角形最小面积并使用优先队列,实现高效地删除指定数量的点,直至达到所需点数。

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

题意:

   给你n+1个点,组成n条边,连续的三个点之间可以构成一个三角形,现在要求你删去其中的某些点,删点的规则是删去三角形面积最小的那个三角形中间的点,直到最后剩下m+1个点。

连接:

  CSU-2116传送门

思路:

   对于每一个点,除了端点外,维护它们的三角形的面积的最小值,以及它所对应的左边相邻的点与右边相邻的点,使用优先队列对面积进行从小到大排序,每次删掉一个点,需要对其两边的三角形进行更新,再将新的两个面积加入,这个时候之前旧的面积就没用了,如果去删除会很费时,可以采用标记的方法,因为如果那个面积的左右点中有一个是不存在的点(也就是已经删除了的点)那就可以说明这个面积是错误的,则跳过,这样时间复杂度便在可接受的范围内。求三角形的面积的方法可以用叉积来求,只需要知道三个点的坐标就可以求出它的面积。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;

const int maxn=200005;
struct node
{
    int x,y,idx,left,right;
    double area;
    bool operator < (const node b) const
    {
        if(area==b.area)
            return idx>b.idx;
        return area>b.area;
    }
} points[maxn];

double get_area(int i)
{
    int left=points[i].left;
    int right=points[i].right;
    double ax=points[left].x-points[i].x;
    double ay=points[left].y-points[i].y;
    double bx=points[right].x-points[i].x;
    double by=points[right].y-points[i].y;
    //cout << ax << ' '<< ay << ' ' << bx << ' ' << by << endl;
    return 0.5*(ax*by-ay*bx);
}
priority_queue<node> Q;
bool used[maxn];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int k=n-m;
    for(int i=0; i<=n; i++)
    {
        scanf("%d%d",&points[i].x,&points[i].y);
        points[i].idx=i;
    }
    memset(used,false,sizeof(used));
    for(int i=1; i<n; i++)
    {
        points[i].left=i-1;
        points[i].right=i+1;
        points[i].area=fabs(get_area(i));
        //cout << i << ' ' << points[i].area << endl;
        Q.push(points[i]);
    }
    points[0].right=1;
    points[n].left=n-1;/*
    while(!Q.empty())
    {
        node temp=Q.top();
        Q.pop();
        cout << temp.idx << ' ' << temp.area << endl;
    }*/
    while(k--)
    {
        node tmp;
        tmp=Q.top();
        Q.pop();
        while(used[tmp.left]||used[tmp.right])
        {
            tmp=Q.top();
            Q.pop();
        }
        int index=tmp.idx;
        printf("%d\n",index);
        used[index]=true;
        int left=points[index].left;
        int right=points[index].right;
        points[left].right=right;
        points[right].left=left;
        if(left>0)
        {
            //cout << "--- left ---" << left << endl;
            points[left].area=fabs(get_area(left));
            Q.push(points[left]);
        }
        if(right<n)
        {
            //cout << "--- right ---" << right << endl;
            points[right].area=fabs(get_area(right));
            Q.push(points[right]);
        }
    }
    return 0;
}

心得:

   其实还是一题简单的模拟题,稍微处理一下细节就好, 做这种题思路需要很清晰,需要考虑好小细节,需要全面考虑。用优先队列与计算几何中的相关内容可以让模拟加快一些

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值