好多特判。。。(我只写了一个)
凸包+Floyd 还学到了怎么判断点线位置
/* 万万没想到是个几何题 首先 z是没用的 因为x,y确定了 那么z就确定了 x,y看做笛卡尔坐标 要是一个东西能被两个东西合成 那么一定在两个东西的连线上 如果是被多个东西合成 那么就是在这几个东西构成的凸包内(圈) 直接n^3判断所有点在不在这条边的同一侧 注意是同一侧 因为要围成 圈 (凸包)嘛 之后就是Floyd跑最小环 注意 在线段上 和在所在直线上和并且在线段外 这两种情况 还要注意点就在线段端点位置。。。 S(P1,P2,P3)=|y1 y2 y3|= (x1-x3)*(y2-y3)-(y1-y3)*(x2-x3) 如果S(A,B,C)为正数,则C在矢量AB的左侧; 如果S(A,B,C)为负数,则C在矢量AB的右侧; 如果S(A,B,C)为0,则C在直线AB上。 这个公式其实就是俩斜率公式 的变形。。。 注意特判全部点都在一起的时候。。。 QwQ函数 */ #include<algorithm> #include<cstring> #include<cstdio> #include<cmath> #define db double const db eps=1e-9; using namespace std; const int N=550; int n,m,dis[N][N]; db x[N],y[N],_x[N],_y[N]; void Init() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lf%lf%*lf",&x[i],&y[i]); for(int i=1;i<=m;i++) scanf("%lf%lf%*lf",&_x[i],&_y[i]); } int Work(int i,int j,int k) { double res=(x[i]-_x[k])*(y[j]-_y[k])-(y[i]-_y[k])*(x[j]-_x[k]); if(fabs(res)<=eps) { if(_x[k]<x[i]&&_x[k]<x[j]) return 2; if(_x[k]>x[i]&&_x[k]>x[j]) return 2; if(_y[k]<y[i]&&_y[k]<y[j]) return 2; if(_y[k]>y[i]&&_y[k]>y[j]) return 2; return 4; } return (res>=0); } void Solve() { memset(dis,0x3f,sizeof(dis)); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i!=j) { int p=0,p0=0,p1=0; for(int k=1;k<=m;k++) { int t=Work(i,j,k); if(t==0||t==2) {p=1;break;} // 只能在同一侧 我们默认为返回 1 是符合条件的吧 都无所谓 // 返回2 是指在所在直线上和并且在线段外 坑定不行 } if(!p) dis[i][j]=1; } } void Floyd() { for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); int ans=dis[0][0]; for(int i=1;i<=n;i++) ans=min(ans,dis[i][i]); if(ans==dis[0][0]) ans=-1; printf("%d\n",ans); } bool QwQ() { for(int i=1;i<=n;i++) { int p=1; for(int j=1;j<=m;j++) if(fabs(x[i]-_x[j])>eps||fabs(y[i]-_y[j])>eps) {p=0;break;} if(p) {puts("1");return 1;} } return 0; } int main() { Init(); if(QwQ()) return 0; Solve(); Floyd(); return 0; }