这个是真的想不到啊
第一你搞三维的没意义
于是乎,把c看做1-a-b那么c就没有了意义,因为确定了a,b辣么c自然确定下来
其次对于这个东西有着重要的引理:
对于二元笛卡尔基上的点(Ax,Ay)(Bx,By)他们的连线就是可以配凑的情况
辣么扩展到多个点进行配凑:由于可把这个线段上的每一个点都看做一种新点,于是这些点的连线可以扩展
呜呼,线的无限重叠就是面了啊!!!
顾:这实际是求多少个点构成的凸包可以包含一个点集
那么我们只要保证两个点的连线的左边或在线段上全是包含点集,那么这条边可以作为凸包的一条边
那么问题的本质是求最小环!!!
floyd就好了(或者说floyd本质是判断有无环但对于此题,只要你不做倍增限制边数那么环就是最小的)
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=501;
const double eps=1e-12;
const double INF=1e12;
int cmp(double A){
if(fabs(A)<eps)return 0;
else return(A>0)?1:-1;
}
struct Point{
double x,y,z;
Point(double _x=0.0,double _y=0.0):x(_x),y(_y){}
friend Point operator + (Point A,Point B){return Point(A.x+B.x,A.y+B.y);}
friend Point operator - (Point A,Point B){return Point(A.x-B.x,A.y-B.y);}
friend Point operator * (Point A,double k){return Point(A.x*k,A.y*k);}
friend Point operator / (Point A,double k){return Point(A.x/k,A.y/k);}
void read(){scanf("%lf%lf%lf",&x,&y,&z);}
}A[N],B[N];
typedef Point Vector;
double Dot(Vector A,Vector B){
return A.x*B.x+A.y*B.y;
}
double Cross(Vector A,Vector B){
return A.x*B.y-A.y*B.x;
}
int m,n;
int mmp[N][N]={};
int main(){
memset(mmp,0x3f,sizeof(mmp));
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++){
A[i].read();
}
for(int i=1;i<=n;i++){
B[i].read();
}
for(int i=1;i<=m;i++){
for(int j=1;j<=m;j++){
int flag=1;
for(int k=1;k<=n;k++){
Vector Vec1=A[i]-B[k];
Vector Vec2=A[j]-B[k];
if(cmp(Cross(Vec1,Vec2))>0){
flag=0;
break;
}
if(cmp(Cross(Vec1,Vec2)==0)&&!((B[k].x<=max(A[i].x,A[j].x))&&(B[k].x>=min(A[i].x,A[j].x))&&(B[k].y<=max(A[i].y,A[j].y))&&(B[k].y>=min(A[i].y,A[j].y)))){
flag=0;
break;
}
}
if(flag==1){
// cout<<i<<" "<<j<<'\n';
mmp[i][j]=1;
}
}
}
int ans=501;
for(int k=1;k<=m;k++){
for(int i=1;i<=m;i++){
for(int j=1;j<=m;j++){
mmp[i][j]=min(mmp[i][k]+mmp[k][j],mmp[i][j]);
}
}
}
for(int i=1;i<=m;i++){
ans=min(ans,mmp[i][i]);
}
if(ans!=501)
cout<<ans;
else cout<<-1;
}