您的位置:首页 > 其它

poj 2653

2016-07-21 23:28 393 查看

题目概述

在坐标系中扔N根粗细不计的木棒,每根木棒的序号为其被扔的序数,若两木棒相交,则后扔的会被视为“在顶端”,先扔的会被压在下面,给出每根木棒端点坐标,求最后有哪些木棒“在顶端”

时限

3000ms/9000ms

输入

每组数据第一行正整数N,其后N行,每行4个浮点数,为木棒端点坐标,输入以N=0结束

限制

1<=N<=100000;1<=“在顶端”木棒数<=1000

输出

每行开头为字符串

Top sticks:

其后若干个数,为“在顶端”的木棒序号,两个数之间以英文逗号和空格分隔,最后输出一个英文句号

样例输入

5

1 1 4 2

2 3 3 1

1 -2.0 8 4

1 4 8 2

3 3 6 -2.0

3

0 0 1 1

1 0 2 1

2 0 3 1

0

样例输出

Top sticks: 2, 4, 5.

Top sticks: 1, 2, 3.

讨论

计算几何,求线段相交,题充其量算模版题(早背过模版了),只是输入量巨大,想快些并不容易,看过几篇题解,通过灵活(但略复杂)运用一个数组的前几个空白位置反复记录,可以将用时降低到400-600ms,额退而求其次,开个链表,效果也说得过去,暴力的平方级方法也试过,然而3秒根本不可能够

为何是“在顶端”呢?因为真正在顶端的应该是摞的最高的那个,而且只有一个,因而加了引号

题解状态

3708K,610MS,G++,1936B

题解代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<list>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 100003
#define memset0(a) memset(a,0,sizeof(a))
#define EPS 1e-6

list<int>marked;//存放“在顶端”的木棒序号
list<int>::iterator it, last;//放到外面也是为了省点常数 last用于指向最后一个元素
double x[MAXN], y[MAXN], x2[MAXN], y2[MAXN];//木棒端点坐标值
inline double xp(double x1, double y1, double x2, double y2, double x3, double y3)
{
return (x1 - x2)*(y3 - y2) - (y1 - y2)*(x3 - x2);
}
inline bool onsegment(double x, double y, double x1, double y1, double x2, double y2)
{
return min(x1, x2) <= x&&x <= max(x1, x2) && min(y1, y2) <= y&&y <= max(y1, y2);
}
inline bool intersect(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
{
double xp1 = xp(x3, y3, x1, y1, x2, y2);
double xp2 = xp(x4, y4, x1, y1, x2, y2);
double xp3 = xp(x1, y1, x3, y3, x4, y4);
double xp4 = xp(x2, y2, x3, y3, x4, y4);
if (xp1*xp2 < 0 && xp3*xp4 < 0)
return 1;
else if (abs(xp1) < EPS&&onsegment(x3, y3, x1, y1, x2, y2))
return 1;
else if (abs(xp2) < EPS&&onsegment(x4, y4, x1, y1, x2, y2))
return 1;
else if (abs(xp3) < EPS&&onsegment(x1, y1, x3, y3, x4, y4))
return 1;
else if (abs(xp4) < EPS&&onsegment(x2, y2, x3, y3, x4, y4))
return 1;
return 0;
}//上面三个函数已经背的很熟练了 今天做了好几个题 也懒得解释了
void fun(int N)
{
for (int p = 0; p < N; p++) {
scanf("%lf%lf%lf%lf", &x[p], &y[p], &x2[p], &y2[p]);//input
marked.push_back(p);
last = marked.end();
--last;//链表没法随机存储 只能这样
for (it = marked.begin(); it != last; ) {
int a = *last, b = *it;//也是为了减小常数
if (intersect(x[a], y[a], x2[a], y2[a], x[b], y[b], x2[b], y2[b]))
marked.erase(it++);//链表节点删除后迭代器也会作废 因而利用后缀++先行将下一节点算出再将旧的删除掉
else
++it;//没删还是照常递增 注意前缀++比后缀要快……一点点
}
}
bool f = 0;//控制逗号空格输出
printf("Top sticks: ");//output
for (it = marked.begin(); it != marked.end(); ++it) {
if (f)
printf(", ");
printf("%d", *it + 1);//output
f = 1;
}
printf(".\n");//output
}
int main(void)
{
//freopen("vs_cin.txt", "r", stdin);
//freopen("vs_cout.txt", "w", stdout);

int N;
while (~scanf("%d", &N) && N) {//input
fun(N);
marked.clear();//链表里有东西 需要清空
}
}


EOF
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: