《L3-009 长城 (30 分)》

一开始一直在想这题,首先烽火站点肯定放在凸点,凹点肯定没后面的凸点更优。

那么主要就在于判断是否这个凸点没有放置的必要。

于是就有一个N^2的做法,去暴力判断。

然后我就开始考虑优化,但是没怎么想出来。

其实并没有那么难。

类似单调栈的思想去维护一个有设立烽火站的凸点的栈。

对于三个点,a,b,c。b为中点。

如果ab的斜率 > bc的斜率,那么这个b的凸点就必须要去放了,不然就会导致c无法看见a。

这样去维护栈即可。

这里肯定有一个疑问,如果c的后面的点可以取带c点来看见a,那么会不会少了这种方案。

答案是不会,因为我们栈中维护的都是有设立的点,如果那个后面的点可以看见a,那么说明那个点也可以看见c。

那么c就不会设立,这样就可以明白,存在栈中的点去看前面很正确。

然后注意,一个点可能会多次去被判断,这样不能重复设立,我们对每个点做一个标记来表示有没有设立,最后统计即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 2e3 + 5;
const LL Mod = 2147483647;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
}
using namespace FASTIO;

LL x[N],y[N];
/*
double k1 = (y[k] - y[j]) / (x[k] - x[j]);
double k2 = (y[j] - y[i]) / (x[j] - x[i]);
能看见 k2 <= k1
(y[k] - y[i]) * (x[k] - x[j]) <= (y[k] - y[j]) * (x[j] - x[i]);
*/
bool check(int i,int j,int k) {//i - now,j - middle,k - right
    return (y[j] - y[i]) * (x[k] - x[j]) <= (y[k] - y[j]) * (x[j] - x[i]);
}
int S[N],vis[N];
int main()
{
    int n;n = read();
    int top = 0;
    for(int i = 1;i <= n;++i) {
        x[i] = read(),y[i] = read();
        while(top >= 2 && check(i,S[top],S[top - 1])) top--;
        vis[S[top]] = 1;
        S[++top] = i;
    }
    int ans = 0;
    for(int i = 2;i <= n;++i) if(vis[i]) ans++;
    printf("%d
",ans);
    system("pause");
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zwjzwj/p/14492276.html