zoukankan      html  css  js  c++  java
  • ZOJ 2967 Colorful Rainbows 【Stack】

    解决此题方法类似于凸包,先把所有直线按照斜率a由小到大排序
    斜率相同取b较大的,扔掉b小的 (可以在遍历的时候忽视)。
    于是所有直线斜率不同。 准备一个栈 (手动模拟), 栈里面存放上一次能看到的“最上面”的直线以及这条直线能看到的范围x (x值右边的部分可以被看到)。 初始时,把斜率最小的直线入栈,并记录x值为-inf。然后对第i条直线, 所做的是用第i条直线和栈顶直线求交点x,如果这个x值不大于栈顶的x值, 则把栈顶元素弹出,继续求交,否则退出。
    这种判断操作直到栈为空, 或者当前栈顶的x值大于栈顶的x值。然后把第i条直线入栈,
    继续,看后面的直线。最后栈中的直线数就是能看到的。 这种做法类似于凸包的方法,除去排序外,每条直线至多出入栈一次 复杂度O(n)。总复杂度是O(nlogn)。

    Source Code:

    //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler
    #include <stdio.h>
    #include <iostream>
    #include <fstream>
    #include <cstring>
    #include <cmath>
    #include <stack>
    #include <string>
    #include <map>
    #include <set>
    #include <list>
    #include <queue>
    #include <vector>
    #include <algorithm>
    #define Max(a,b) (((a) > (b)) ? (a) : (b))
    #define Min(a,b) (((a) < (b)) ? (a) : (b))
    #define Abs(x) (((x) > 0) ? (x) : (-(x)))
    #define MOD 1000000007
    #define pi acos(-1.0)
    
    using namespace std;
    
    typedef long long           ll      ;
    typedef unsigned long long  ull     ;
    typedef unsigned int        uint    ;
    typedef unsigned char       uchar   ;
    
    template<class T> inline void checkmin(T &a,T b){if(a>b) a=b;}
    template<class T> inline void checkmax(T &a,T b){if(a<b) a=b;}
    
    const double eps = 1e-8         ;
    const int N = 210               ;
    const int M = 1100011*2         ;
    const ll P = 10000000097ll      ;
    const int MAXN = 10900000       ;
    const double MINN = -999999999.9;
    
    int n;
    
    struct Line{
        double a, b;
    }line[5001];
    
    struct Point{
        int ID;
        double x;   //Crossover point
    }point[5001];
    
    bool cmp (Line a , Line b){
        if(a.a != b.a)  return a.a < b.a ;
        return a.b > b.b;
    }
    
    int main(){
        int i, j, t, k, u, v, numCase = 0;
        cin >> t;
        while (t--){
            int sum = 0;
            cin >> n;
            for (i = 0; i < n; ++i) {
                cin >> line[i].a >> line[i].b;
            }
            sort (line , line + n, cmp);
    
            point[sum].ID = 0;
            point[sum].x = MINN;
    
            for (i = 1; i < n; ++i) {
                if (Abs (line[i].a - line[point[sum].ID].a) < eps)    continue; //Equal slope will be ignored
                for (;;) {
                    if (sum < 0) {
                        ++sum;
                        point[sum].ID = i;
                        point[sum].x = MINN;
                        break;
                    }
                    double x = (line[point[sum].ID].b - line[i].b) / (line[i].a - line[point[sum].ID].a);
                    if (point[sum].x + eps > x) {
                        --sum;
                    } else {
                        ++sum;
                        point[sum].ID = i;
                        point[sum].x = x;
                        break;
                    }
                }
            }
            printf("%d
    ", 1 + sum);
         }
    
         return 0 ;
    }

    以下是另一种 O(n lg n) 的算法 @Sake

    对于直线l1: y = a1x +b1 和直线l2: y = a2x + b2,假设 a2 > a1,同时已知l1和前面面
    一一个斜率更小小的交点横坐标为x1,则l2和l1的交点横坐标为x2,如果x2 < x1,那么l2可以覆盖
    l1的可⻅见段。这样对于l2处理栈中的栈顶直线,若可以覆盖,栈顶弹出,循环直到栈中只有一一条直线或者不能继续覆盖,最后将这条直线压入入栈。对于只有1条或者2条直线的情况,特殊处理即可。
    效率为O(n lg n)。
    当然这题,可以按题⺫目目描述模拟暴力力O(n^2)过。
    
    /*
    Author:
    */
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    sakeven
    <cstdio>
    <cstdlib>
    <cassert>
    <iostream>
    <algorithm>
    <queue>
    <stack>
    <cmath>
    <cstring>
    using namespace std;
    struct node{
    double a,b;
    }lines[5100];
    struct point{
    int index;
    double x;
    point(){}
    point(int index, double x):index(index), x(x){}
    };
    bool cmp(const node &A, const node &B){
    return A.a < B.a || (A.a == B.a && A.b < B.b);
    }
    int main(){
    int t, n;
    scanf("%d", &t);
    while (t--) {
    scanf("%d", &n);
    for (int i = 0; i < n; i ++) {
    scanf("%lf%lf", &lines[i].a , &lines[i].b);
    }
    sort(lines, lines+n, cmp);
    int k = 0;
    for (int i = 0; i < n-1; i ++) {
    if (lines[i].a == lines[i+1].a) {
    continue;
    }
    lines[k++] = lines[i];
    }
    lines[k++] = lines[n-1];
    if (k <= 2) {
    printf("%d
    ", k);
    continue;
    }point p;
    stack<point>st;
    st.push(point(0, 0));
    st.push(point(1, (lines[1].b - lines[0].b)/(lines[0].a - lines[1].a)));
    for (int i = 2; i < k; i ++) {
    double x(0);
    while (st.size() > 1) {
    p = st.top();
    x = (lines[p.index].b - lines[i].b)/(lines[i].a - lines[p.index].a);
    if (x <= p.x) {
    st.pop();
    if (st.size() == 1) {
    x = (lines[0].b - lines[i].b)/(lines[i].a - lines[0].a);
    break;
    }
    } else {
    break;
    }
    }
    st.push(point(i, x));
    }
    printf("%lu
    ", st.size());
    }
    return 0;
    }

      

  • 相关阅读:
    USACO 玛丽卡(最短路+枚举)
    POJ 1161 Walls(最短路+枚举)
    Windows 上配置Docker Desktop 的k8s
    菜鸡学算法--70. 爬楼梯
    CLR 异步函数
    【.NET Core开发实战学习笔记】依赖注入框架:管理服务的依赖与生命周期
    【.NET Core 开发实战学习笔记】StartUp:理解程序的启动过程
    .ef core 多对对关系的关联方法
    HttpGet请求传递数组(集合)
    使用wkhtmltopdf工具生成pdf
  • 原文地址:https://www.cnblogs.com/wushuaiyi/p/4376157.html
Copyright © 2011-2022 走看看