BZOJ 1007: [HNOI2008]水平可见直线 几何


按斜率排序,斜率线相同的直线取截距最大的

一条直线能够被看到的条件是,与比它斜率小的交点在比它斜率大的交点的左侧

1007: [HNOI2008]水平可见直线

Time Limit: 1 Sec   Memory Limit: 162 MB
Submit: 4234   Solved: 1558
[ Submit][ Status][ Discuss]

Description

 在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则Li为被覆盖的.
    例如,对于直线:
    L1:y=x; L2:y=-x; L3:y=0
    则L1和L2是可见的,L3是被覆盖的.
    给出n条直线,表示成y=Ax+B的形式(|A|,|B|<=500000),且n条直线两两不重合.求出所有可见的直线.

Input

第一行为N(0 < N < 50000),接下来的N行输入Ai,Bi

Output

从小到大输出可见直线的编号,两两中间用空格隔开,最后一个数字后面也必须有个空格

Sample Input

3
-1 0
1 0
0 0

Sample Output

1 2

HINT




C++:

/* ***********************************************
Author        :CKboss
Created Time  :2015年05月10日 星期日 08时38分36秒
File Name     :BZOJ1007.cpp
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>

using namespace std;

const int maxn=50500;

int n;
struct Line
{
	int id;
	int k,b;
}line[maxn];

bool cmp(Line A,Line B)
{
	if(A.k!=B.k) return A.k<B.k;
	return A.b>B.b;
}

Line stack[maxn];
int st;

double cal(Line X,Line Y) /// Line X < Line Y
{
	return (double)(Y.b-X.b)/(X.k-Y.k);
}

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);

	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		line[i]=(Line){i+1,x,y};
	}
	sort(line,line+n,cmp);
	int m=0;
	int lastk=8888888;
	for(int i=0;i<n;i++)
	{
		if(lastk!=line[i].k) 
		{
			line[m++]=line[i];
			lastk=line[i].k;
		}
	}
	n=m;
	stack[st++]=line[0];

	for(int i=1;i<n;i++)
	{
		while(st>1&&cal(stack[st-2],stack[st-1])>=cal(stack[st-1],line[i]))
			st--;
		stack[st++]=line[i];
	}

	vector<int> v;
	for(int i=0;i<st;i++) v.push_back(stack[i].id);
	sort(v.begin(),v.end());
	for(int i=0;i<st;i++)
		printf("%d ",v[i]);
	putchar(10);
    
    return 0;
}



JAVA:

import java.util.*;

public class Main {
	
	final int maxn=50500;
	final double eps = 1e-7;
	
	int n;
	
	public class Line{
		public int k,b,id;
	}
	
	public class cmp1 implements Comparator{
		public int compare(Object x,Object y){
			Line A=(Line)x,B=(Line)y;
			if(A.k!=B.k) return A.k-B.k;
			return B.b-A.b;
		}
	}
	
	Line[] line=new Line[maxn];

	double CAL(Line A,Line B){
		return (double)(B.b-A.b)/(A.k-B.k);
	}
	
	Line[] Stack=new Line[maxn];
	int st;
	
    public Main() {
    	
    	Scanner in = new Scanner(System.in);
    	n=in.nextInt();
    	for(int i=0;i<n;i++){
			line[i]=new Line();
    		line[i].k=in.nextInt();
    		line[i].b=in.nextInt();
			line[i].id=i+1;
    	}
    	Arrays.sort(line,0,n,new cmp1());
		int last=888888;
		int m=0;
    	for(int i=0;i<n;i++){
			if(line[i].k!=last){
				line[m++]=line[i];
				last=line[i].k;
			}
    	}
		n=m;
		Stack[0]=line[0]; st=1;
		for(int i=1;i<n;i++){
			while(st>1&&CAL(Stack[st-1],Stack[st-2])>=CAL(Stack[st-1],line[i])) 
				st--;
			Stack[st++]=line[i];
		}

		Vector vi=new Vector<Integer>();
		for(int i=0;i<st;i++){
			vi.add(Stack[i].id);
		}
		Collections.sort(vi);
		for(int i=0;i<st;i++){
			System.out.printf("%d ",vi.get(i));
		}
    }
    
    public static void main(String[] args){
    	new Main();
    }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值