这个是真的想不到啊
第一你搞三维的没意义
于是乎,把c看做1-a-b那么c就没有了意义,因为确定了a,b辣么c自然确定下来
其次对于这个东西有着重要的引理:
对于二元笛卡尔基上的点(Ax,Ay)(Bx,By)他们的连线就是可以配凑的情况
辣么扩展到多个点进行配凑:由于可把这个线段上的每一个点都看做一种新点,于是这些点的连线可以扩展
呜呼,线的无限重叠就是面了啊!!!
顾:这实际是求多少个点构成的凸包可以包含一个点集
那么我们只要保证两个点的连线的左边或在线段上全是包含点集,那么这条边可以作为凸包的一条边
那么问题的本质是求最小环!!!
floyd就好了(或者说floyd本质是判断有无环但对于此题,只要你不做倍增限制边数那么环就是最小的)
#include#include #include #include #include using namespace std;const int N=501;const double eps=1e-12;const double INF=1e12;int cmp(double A){ if(fabs(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< <<" "< <<'\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<