Gym - 101635K - 凸包+(三分或叉积)

版权声明:欢迎随便转载。 https://blog.csdn.net/a1214034447/article/details/83383751

题目链接:https://vjudge.net/problem/Gym-101635K

解题思路:

寻找最小覆盖矩形使得能把蛋糕上面所有的点都覆盖,求出他的宽度,高度不限.

那么首先求出n个点组成的凸包.枚举凸包上的所有边,再找凸包上的一个离这条边最远的点,经过此点做边的平行线。

那么此两条平行线无限延长肯定能覆盖所有的点,宽度就是两平行直线的距离.

取每条边都这么做然后最后取答案最小的那一条边.

那么怎么找到边对应的那个点呢?

1.我们按凸包逆时针点枚举,对应边的那个最远点,一定是个"凸值",即逆时针枚举距离值会先增后减,(特殊情况是一开始枚举第一个点就是极值),求凸值就可以用三分来求,因为特殊情况有可能不是凸函数,所以区间至少保留4个以上,3个时退出.

2.叉积法同样是按逆时针枚举凸包上的点,假设现在考虑边(i,i+1),做向量(i+1)->i,从(i+1)->(i+2),(i+2)->(i+3)。。。直到两个叉积>=0

也就是(i+1)->i*j->(j+1)>=0 , 那么j点就是最远的,可以用叉积面积方式理解(底是边(i,i+1),高就是点到直线距离),也可以很容易理解用j这个点做边的平行线,所有点一定都会被夹在中间.

三分法:

#include<math.h>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
const int mx = 2e5 + 10;
int n,top,_x,_y,q[mx*2],m;
double len;
struct node
{
	ll x,y;
}s[mx],tubeg[mx],w;
ll judge(node p1,node p2,node p0)//面积公式判断正负值 
{
	ll ans = (p1.x-p0.x)*(p2.y-p0.y) - (p2.x-p0.x)*(p1.y-p0.y);
	return ans; 
}
bool cmp(node a,node b)
{
	ll c = judge(w,b,a);//极角排序,同角度按距离从小到大排 
	if(!c) return pow(a.x-w.x,2)+pow(a.y-w.y,2) < pow(b.x-w.x,2)+pow(b.y-w.y,2);
	return c < 0;
}
void Graham()
{
	for(int i=0;i<n;i++)
	{
		while(top>1&&judge(tubeg[top-2],s[i],tubeg[top-1])>=0) top--;//在矢量左侧的点都去掉 
		tubeg[top++] = s[i];
	}
}
double dist(node a,node b)
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double across(node c,node a,node b)
{
	return fabs((c.y-a.y)*(b.x-a.x) - (c.x-a.x)*(b.y-a.y));
}
double Get(int x,node a,node b)
{
	node c = tubeg[x];
	return across(c,a,b) / len;
}
double sanfen(int l,int r,node a,node b)
{
	while(l<r-2){
		int mid = (l+r)>>1;
		int mmid = mid+1;
		if(Get(q[mid],a,b)>Get(q[mmid],a,b))
		r = mmid;
		else l = mid;
	}
	return max(Get(q[l],a,b),max(Get(q[r],a,b),Get(q[r-1],a,b)));
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		int a,b,p = 0;
		for(int i=0;i<n;i++){
			scanf("%lld%lld",&s[i].x,&s[i].y);
			if(s[i].y<s[p].y) p = i;
			else if(s[i].y==s[p].y&&s[i].x<s[p].x) p = i;
		}
		swap(s[0],s[p]),w.x = s[0].x,w.y = s[0].y;
		sort(s+1,s+n,cmp);//以最下左那个坐标为参考坐标做极角排序 
		Graham();
		double ans = 1e9;
		int l = 0, r = 0,eng = top-1;
		for(int i=2;i<top;i++) q[r++] = i;
		for(int i=0;i<top;i++){
			len = dist(tubeg[i],tubeg[(i+1)%top]);
			ans = min(ans,sanfen(l,r-1,tubeg[i],tubeg[(i+1)%top]));
			eng = (eng+1)%top;
			l++,q[r++] = eng;
		}
		len =  dist(tubeg[0],tubeg[1]);
		printf("%.10lf\n",ans);
	}
	return 0;
} 

叉积法:

#include<math.h>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
const int mx = 2e5 + 10;
int n,top,_x,_y,m;
double len;
struct node
{
	ll x,y;
}s[mx],tubeg[mx],w;
ll judge(node p1,node p2,node p0)//面积公式判断正负值 
{
	ll ans = (p1.x-p0.x)*(p2.y-p0.y) - (p2.x-p0.x)*(p1.y-p0.y);
	return ans; 
}
ll judge2(node a,node b)
{
	return a.x*b.y - b.x*a.y;
}
bool cmp(node a,node b)
{
	ll c = judge(w,b,a);//极角排序,同角度按距离从小到大排 
	if(!c) return pow(a.x-w.x,2)+pow(a.y-w.y,2) < pow(b.x-w.x,2)+pow(b.y-w.y,2);
	return c < 0;
}
void Graham()
{
	for(int i=0;i<n;i++)
	{
		while(top>1&&judge(tubeg[top-2],s[i],tubeg[top-1])>=0) top--;//在矢量左侧的点都去掉 
		tubeg[top++] = s[i];
	}
}
double dist(node a,node b)
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double Get(int x,node a,node b)
{
	node c = tubeg[x];
	return fabs( judge(b,c,a) / len );
}
node cut(node a,node b)
{
	return node{a.x-b.x,a.y-b.y};
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		int a,b,p = 0;
		for(int i=0;i<n;i++){
			scanf("%lld%lld",&s[i].x,&s[i].y);
			if(s[i].y<s[p].y) p = i;
			else if(s[i].y==s[p].y&&s[i].x<s[p].x) p = i;
		}
		swap(s[0],s[p]),w.x = s[0].x,w.y = s[0].y;
		sort(s+1,s+n,cmp);
		Graham();
		double ans = 1e9;
		int head = 1;
		for(int i=0;i<top;i++){
			len = dist(tubeg[i],tubeg[(i+1)%top]);
			node now = cut(tubeg[i],tubeg[(i+1)%top]);
			while(judge2(now,cut(tubeg[(head+1)%top],tubeg[head]))<0)
			head = (head+1)%top;
			ans = min(ans,Get(head,tubeg[i],tubeg[(i+1)%top]));
		}
		printf("%.10lf\n",ans);
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/a1214034447/article/details/83383751