【JZOJ5094】【GDSOI2017第四轮模拟day3】鸽子 计算几何+floyd

题面

养鸽人要监视他的鸽子,有n只鸽子站在平面上,他可以在m个给定的点上设置监视器,如果一只鸽子在某个监视器上或者在两个监视器所连直线上或者在三个监视器所连直线的三角形内则其就咕咕咕了,现在养鸽人要让所有鸽子咕咕咕,请问他最少需要设置多少监视器。
对于100%的数据n≤100000,m≤500,坐标绝对值不超过10的9次方。

100

首先转化一下题意,就是选取尽量少的点,然后生成一个凸包,包住给定的一个凸包。
显然在给定凸包内的点是没有用处的。
对于不在给定凸包内的点,我们枚举它们:
对于一个点i,找出其与给定凸包的两条“切线”。

如图,两条切线即为x,y,那么就有使(i)给图中蓝色的点连一条长度为1的边。
由于凸包是,一个点出发,回到这个点的最短路。
然后做一遍floyd就可以了。

Code

#include<bits/stdc++.h>
#define ll long long
#define db double
#define fo(i,x,y) for(int i=x;i<=y;i++)
#define fd(i,x,y) for(int i=x;i>=y;i--)
using namespace std;
const int inf=0x7fffffff;
const char* fin="pigeon.in";
const char* fout="pigeon.out";
const int maxn=100007,maxm=507;
const db eps=1e-10;
int equ(db v,db c){return (fabs(v-c)<eps?0:(v<c?-1:1));}
struct P{
	db x,y;
	P(db _x=0,db _y=0){x=_x;y=_y;}
	P operator +(const P &b)const{return P(x+b.x,y+b.y);}
	P operator -(const P &b)const{return P(x-b.x,y-b.y);}
	db operator ^(const P &b)const{return x*b.y-b.x*y;}
	db arg()const{return atan2(y,x);}
	void ni(){x=-x;y=-y;}
	void p(){printf("%lf %lf
",x,y);}
}a[maxn],b[maxm],c[maxn];
int n,m,N,f[maxm][maxm];
void floyd(){
	fo(k,1,m) fo(i,1,m) fo(j,1,m)
		if (f[i][k]<2000000000 && f[k][j]<2000000000)
			f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
}
int main(){
	freopen(fin,"r",stdin);
	freopen(fout,"w",stdout);
	scanf("%d%d",&n,&m);
	fo(i,1,n) scanf("%lf%lf",&a[i].x,&a[i].y);
	fo(i,1,m) scanf("%lf%lf",&b[i].x,&b[i].y);
	memset(f,127,sizeof f);
	bool debug=false;
	fo(i,1,m){
		int mxid=0,mnid=0,lid=0,hid=0;
		db low,high;
		P mx,mn;
		fo(j,1,n){
			if (a[j].x==b[i].x && a[j].y==b[i].y) continue;
			db x=(a[j]-b[i])^(a[1]-b[i]);
			P tmp=(a[j]-b[i]);
			if (mxid==0 || equ(mx^tmp,0)>0) mx=tmp,mxid=j;
			if (mnid==0 || equ(mn^tmp,0)<0) mn=tmp,mnid=j;
			if (hid==0 || high<x) high=x,hid=j;
			if (lid==0 || low>x) low=x,lid=j;
		}
		if (equ((a[hid]-b[i])^(a[lid]-b[i]),0)<0) continue;
		P da=mx,xiao=mn;
		if (debug) xiao.p(),da.p();
		da.ni();
		fo(j,1,m)
			if (i!=j){
				P tmp=b[j]-b[i];
				if (debug){
					tmp.p();//printf(":%lf %lf
",xiao^tmp,tmp^da);
					printf(":%d %d
",equ(xiao^tmp,0)<=0,equ(tmp^da,0)<=0);
				}
				if (equ(xiao^tmp,0)<=0 && equ(tmp^da,0)<=0) f[i][j]=1;
			}
		if (debug)printf("
");
	}
	floyd();
	int ans=inf;
	fo(i,1,m) ans=min(ans,f[i][i]);
	if (ans<2000000000) printf("%d",ans);
	else printf("-1");
	return 0;
}
原文地址:https://www.cnblogs.com/hiweibolu/p/6774648.html