Pick-up sticks POJ - 2653

题目链接:POJ - 2653

首先这题数据n<100000可能没错,但只要边添加,边判断弹出的话,还是可以直接用双for来判断。

1.边判断弹出怎么实现?

链表似乎是很不错的,从前往后遍历,不行的O(1)弹出,但不管是手写指针链表,stl链表,还是数组链表都麻烦些(还是不太会QAQ)。可以用两个队列来实现,每次弹空一个,判断是否压入另一个,注意下最后输出答案是从小到大的

2.判断线段相交呢?

先判断是否平行

重合的话返回YES,平行的话返回NO

不平行的话

当做判断直线和线段相交,只不过判定两遍,两个线段分别做一次直线和线段,如果两次直线和线段都相交返回YES(这个方法这题是没问题,仔细想想好像没什么问题,甚至上面的平行都不用判断

否则返回NO

代码

#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<utility>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define inf 0x3f3f3f3f
#define ll long long
#define dou double
#define EXP 1e-6
#define M 1000005
int n;
struct P{
    double x,y;
    P(double x=0,double y=0):x(x),y(y){}
};
struct L{
    P a,b;
    int id;
    L(){}
    L(P a,P b):a(a),b(b){}
}cnt;
queue<L>q[2];
double area(P a,P b,P c){
    return fabs((b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y))/2;
}
bool par(L a,L b){      //判断线段是否平行(重合和平行)
    return fabs((a.b.x-a.a.x)*(b.b.y-b.a.y)-(b.b.x-b.a.x)*(a.b.y-a.a.y))<EXP;
}
dou cross(P mark,P a,P b){             //在向量a->b的左边
    return (a.x-mark.x)*(b.y-mark.y)-(b.x-mark.x)*(a.y-mark.y);
}
int inte(L x,P a,P b)
{
    return cross(a,x.a,x.b)*cross(b,x.a,x.b)<EXP;
}
int f(L x,L y){
    if(par(x,y)){           //平行
        if(area(y.a,x.a,x.b)>EXP) return 1;        //平行
        return 0;         //重合
    }
    return !(inte(x,y.a,y.b)&&inte(y,x.a,x.b));
}
void add(L x,int d){
    while(!q[d%2].empty()){
        if(f(q[d%2].front(),x)) q[(d+1)%2].push(q[d%2].front());
        q[d%2].pop();
    }
    q[(d+1)%2].push(x);
}
int main(){
    while(cin>>n&&n){
        fo(1,n){
            cin>>cnt.a.x>>cnt.a.y>>cnt.b.x>>cnt.b.y;
            cnt.id=i;
            add(cnt,i);
        }
        printf("Top sticks:");
        int now=(n+1)%2;
        while(!q[now].empty()){
            printf(" %d%c",q[now].front().id,q[now].size()==1?'.':',');
            q[now].pop();
        }
        printf("\n");
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

int 我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值