BZOJ P1027[JSOI2007]合金

大概算是第一道的计算几何题??

我们可以发现给出的三个量相加等于一,别跟我说样例,所以可以忽略一项

然后我们可以发现,如果要混合出一样东西,假设是x1,y1.x2,y2混合出x3,y3

(x1<x2,y1<y2)那么可以发现x1<x3<x2&&y1<y3<y2

所以题目就是要找一些点这些点连出来的多边形可以包含所有点

这样就是个凸包了,然后floyed跑个最短路

我的注释多详细

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#define eps 1e-10
#define inf 100000000
using namespace std;
struct P{
	double x,y;
};
P a[505],b[505];
int dis[505][505],mp[505][505],n,m;
double operator*(P a,P b){
	return a.x*b.y-a.y*b.x;
}//求点积 
P operator-(P a,P b){
	P t;
	t.x=a.x-b.x;
	t.y=a.y-b.y;
	return t;
}//点的差求出向量 
bool col(P x,P y){
	if(x.x>y.x){
		swap(x,y);
	}
	for(int i=1;i<=m;i++){
		if(b[i].x<x.x||b[i].x>y.x){
			return 0;
		}
	}//判断是否都在x,y的线段上 
	if(x.y>y.y){
		swap(x,y);
	}
	for(int i=1;i<=m;i++){
		if(b[i].y<x.y||b[i].y>y.y){
			return 0;
		}
	}//判断是否都在x,y的线段上 
	return 1;
}
int jud(P x,P y){
	int c1=0,c2=0;
	for(int i=1;i<=m;i++){
		double t=(y-x)*(b[i]-x);//点积来计算两个向量的位置关系 
		if(t>eps){
			c1++;
		}//在顺时针位置 
		if(t<-eps){
			c2++;
		}//逆时针 
		if(c1*c2){
			return 0;
		}//两边都有的话,直接不连边 
	}
	if(!c1&&!c2&&col(x,y)){
		cout<<2<<endl;
		return -1;
	}//如果正好在这条线上,并且所有点都可以被包住,直接输出2 
	if(c1){
		return 1;
	}//如果只有顺时针 
	if(c2){
		return 2;
	}//只有逆时针 
	return 3;//第五种情况就是所有点在同一直线但是x,y并不包含所有点 
}
void floyd(){
	int ans=inf;
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			if(dis[i][k]<inf){
				for(int j=1;j<=n;j++){
					dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
				}
			}
		}
	}//floyed求一下传递闭包,最短路 
	for(int i=1;i<=n;i++){
		ans=min(ans,dis[i][i]);
	}//算一算以一个点为顶点的传递闭包的最短路 
	if(ans==inf||ans<=2){
		cout<<"-1"<<endl;
	}else{
		printf("%d",ans);
	}
}
void solve(){
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			int flag=jud(a[i],a[j]);
			if(flag==-1){
				return;
			}//已经包住了,返回 
			if(flag==1){
				dis[i][j]=1;//都在左侧 
			}else if(flag==2){
				dis[j][i]=1;//都在右侧 
			}else if(flag==3){
				dis[i][j]=dis[j][i]=1;//都在线上 
			}
		}
	}
	floyd();//求传递闭包 
}
bool spj(){
	for(int i=1;i<=n;i++){
		if(fabs(a[i].x-a[1].x)>eps||fabs(a[i].y-a[1].y)>eps){
			return 0;
		}
	}
	for(int i=1;i<=m;i++){
		if(fabs(b[i].x-a[1].x)>eps||fabs(b[i].y-a[1].y)>eps){
			return 0;
		}
	}
	puts("1");
	return 1;
}
int main(){
	memset(dis,127/3,sizeof(dis));
	cin>>n>>m;
	double K;
	for(int i=1;i<=n;i++){
		cin>>a[i].x>>a[i].y>>K;
	}//这个K。。。。 
	for(int i=1;i<=m;i++){
		cin>>b[i].x>>b[i].y>>K;
	}//这个K。。。。 
	if(spj()){
		return 0;
	}
	solve();
	return 0;
}
/*

in:
3 2
0.25 0.25 0.5
0 0.6 0.4
1 0 0
0.7 0.1 0.2
0.85 0.05 0.1

out:
2

*/ 


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值