BZOJ 1007 [HNOI2008]水平可見直線===數學相關

題目鏈接:點我傳送

(第一道不看題解過的題目==2333333


=====思考過程

先是想到最左邊肯定是斜率最小的,最右邊肯定是最大的(因爲x趨近於-∞時斜率小的算出來大,因爲x趨近於+∞時斜率大的算出來大。

於是就想到了把直線按照k從小到大排序。

後來又想到,k相等時,只有b最大的直線會出鏡,別的不用管,所以排序時順便去掉這些無用線。

於是就想到,三條直線Y1,Y2,Y3,滿足K1<K2<K3,那麼窩萌來考慮Y3遮住Y2的條件。


發現當且僅當Y3與Y2的交點比Y3和Y1的交點右邊時,Y2會存在,否則會被Y3遮住。


#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <windows.h>
#define rep(j,k,l) for (int j=k;j<=l;j++)

using namespace std;
int pr[55555],haha[55555];

struct lych{
	
	double x,y;
	int num;
	
} line[55555];

bool cmp(const lych &xx,const lych &yy){
	
	if (xx.x==yy.x) return xx.y>yy.y;
	return  xx.x<yy.x;
	
}

double cll(lych xx,lych yy){
	
	return 1.0*(xx.y-yy.y)/(yy.x-xx.x);
	
}

double cl(int xx,int yy){
	
	return cll(line[pr[xx]],line[yy]);
	
}

int n;

int main(){
	
	//freopen("in.txt","r",stdin);
	//freopen("1007.out","w",stdout);
	scanf("%d",&n);
	rep(i,1,n) scanf("%lf%lf",&line[i].x,&line[i].y),line[i].num=i;
	sort(line+1,line+n+1,cmp);int ans=0;
	//rep(i,1,n) printf("%.6f %.6f %d\n",line[i].x,line[i].y,line[i].num);
	rep(i,1,n) if (i==1||line[i].x!=line[i-1].x){
		
		//printf("%d\n",i);
		if (ans<2){
			
			ans++;
			pr[ans]=i;
			haha[ans]=line[i].num;
			//printf("ok");
			continue;
			
		}
		//printf("%.6f %.6f\n",cl(ans,i),cl(i,ans-1));
		if (cl(ans,i)>cl(ans-1,i)){
			
			//printf("%.6f %.6f\n",cl(ans,i),cl(i,ans-1));
			ans++;
			pr[ans]=i;
			haha[ans]=line[i].num;
			
		}
		else{
			
			pr[ans]=i;
			haha[ans]=line[i].num;
			
		}
		//rep(i,1,ans) printf("%d ",haha[i]);
		//printf("\n");
		while (ans>=3&&cl(ans-1,i)<=cl(ans-2,i)){
			
			ans--;
			pr[ans]=pr[ans+1];
			haha[ans]=haha[ans+1];
			
		}
		//rep(i,1,ans) printf("%d ",haha[i]);
		//printf("\n");
		
	}
	sort(haha+1,haha+ans+1);
	rep(i,1,ans) printf("%d ",haha[i]);
	printf("\n");
	system("pause");
	return 0;
	
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章