bzoj [JSOI2010]Group 部落劃分 Group【二分+並查集】
阿新 • • 發佈:2018-07-30
group print i++ end cst col sqrt 部落 har
我是zz嗎這麽簡單都寫錯……
一眼二分,然後判斷的話是枚舉點,然後計算這個點到已有聯通塊的最小距離,如果這個點到一些聯通塊的距離小於當前二分的val,則把這些聯通塊合並起來,這裏用並查集維護,最後看這樣得出的部落數是否大於k(多出來的可以直接合並)
有個非常小的優化就是不用double二分,直接把點兩兩之間的距離存起來排個序,直接在排序後數組裏二分即可
#include<iostream> #include<cstdio> #include<cmath> #include<vector> #include<cstring> #include<algorithm> using namespace std; const int N=1005; int n,m,x[N],y[N],f[N],tot; double mn[N],d[N*N]; int read() { int r=0,f=1; char p=getchar(); while(p>‘9‘||p<‘0‘) { if(p==‘-‘) f=-1; p=getchar(); } while(p>=‘0‘&&p<=‘9‘) { r=r*10+p-48; p=getchar(); } return r*f; } double dis(double x1,double y1,double x2,double y2) { return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } int zhao(int x) { return x==f[x]?x:f[x]=zhao(f[x]); } bool ok(double va) { int col=0; for(int i=1;i<=n;i++) f[i]=i; for(int i=1;i<=n;i++) { int s=0,w; for(int j=1;j<=n;j++) mn[j]=1e9; for(int j=1;j<i;j++) { int nw=zhao(j); mn[nw]=min(mn[nw],dis(x[i],y[i],x[j],y[j])); } for(int j=1;j<i;j++) if(f[j]==j&&mn[j]<va) s++,w=j; if(s>1) { for(int j=1;j<i;j++) if(f[j]==j&&mn[j]<va&&j!=w) f[j]=w; f[i]=w; } else if(s==1) f[i]=w; } for(int i=1;i<=n;i++) if(f[i]==i) col++; // printf("%.2lf %d\n",va,col); // for(int i=1;i<=n;i++) // cerr<<zhao(i)<<" "; // cerr<<endl; return col>=m; } int main() { n=read(),m=read(); for(int i=1;i<=n;i++) { x[i]=read(),y[i]=read(); for(int j=1;j<i;j++) d[++tot]=dis(x[i],y[i],x[j],y[j]); } sort(d+1,d+1+tot); int l=0,r=tot,ans; while(l<=r) { int mid=(l+r)>>1; if(ok(d[mid])) l=mid+1,ans=mid; else r=mid-1; } printf("%.2lf\n",d[ans]); return 0; }
bzoj [JSOI2010]Group 部落劃分 Group【二分+並查集】