BZOJ-1027 [JSOI2007]合金
首先,我们可以舍弃掉第三维,那样的话每种金属就是平面上的点了。
对于任意两个点x,y,假如用户点都不在右边,则从x至y连条长度为1的有向边。
然后Flody求个最小环。
#include <cstdlib> #include <cstdio> #include <iostream> #include <cstring> #include <cmath> #include <cctype> #include <algorithm> #define rep(i, l, r) for(int i=l; i<=r; i++) #define pi acos(-1) #define eps 1e-8 #define inf 0x3fffffff #define maxn 509 typedef long long ll; using namespace std; inline int read() { int x=0, f=1; char ch=getchar(); while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)) x=x*10+ch-'0', ch=getchar(); return x*f; } struct P{double x, y;} k[maxn], q[maxn]; P operator - (P a, P b){return (P){a.x-b.x, a.y-b.y};} double operator * (P a, P b){return a.x*b.y-a.y*b.x;} int n, m, d[maxn][maxn]; inline bool spj() { rep(i, 2, n) if (abs(k[i].x-k[1].x)>eps || abs(k[i].y-k[1].y)>eps) return 0; rep(i, 1, m) if (abs(q[i].x-k[1].x)>eps || abs(q[i].y-k[1].y)>eps) return 0; puts("1"); return 1; } inline bool cos(P a, P b) { if (a.x>b.x) swap(a, b); rep(i, 1, m) if (q[i].x<a.x || b.x<q[i].x) return 0; if (a.y>b.y) swap(a, b); rep(i, 1, m) if (q[i].y<a.y || b.y<q[i].y) return 0; return 1; } inline int jud(P a, P b) { int c1=0, c2=0; rep(i, 1, m) { double t=(b-a)*(q[i]-a); if (t>eps) c1++; if (t<-eps) c2++; if (c1*c2) return 0; } if (!c1&&!c2&&cos(a, b)) {puts("2"); return -1;} if (!c2) return 1; if (!c1) return 2; return 3; } int main() { n=read(), m=read(); double tmp; rep(i, 1, n) scanf("%lf%lf%lf", &k[i].x, &k[i].y, &tmp); rep(i, 1, m) scanf("%lf%lf%lf", &q[i].x, &q[i].y, &tmp); if (spj()) return 0; rep(i, 1, n) rep(j, 1, n) d[i][j]=inf; rep(i, 1, n) rep(j, i+1, n) { int flag=jud(k[i], k[j]); if (flag==-1) return 0; if (flag==1) d[i][j]=1; if (flag==2) d[j][i]=1; if (flag==3) d[i][j]=d[j][i]=1; } rep(i, 1, n) rep(j, 1, n) rep(o, 1, n) if (d[i][j]>d[i][o]+d[o][j]) d[i][j]=d[i][o]+d[o][j]; int ans=inf; rep(i, 1, n) if (d[i][i]<ans) ans=d[i][i]; if (ans<3 || ans==inf) ans=-1; printf("%d\n", ans); return 0; }