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\n", 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\n", 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\n", st.size());

}

return 0;

}

 

  

你可能感兴趣的:(stack)