3 2 0 0 10 0 0 20
22.36
此题是一个最大团的变形问题,题目给出k,和n个点,求出n个点之间的距离,让你求出最小的lim,两点距离大于lim算连通,使得最大团的顶点数不小于k。距离方面可以用二分的思想来优化,而最大团直接套小编给出的最大团模板即可。
#include <math.h> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; const int maxn=50+10; int g[maxn][maxn],dp[maxn],stk[maxn][maxn],mx; void dfs(int n, int ns, int dep) { if (ns == 0) { if (dep > mx) mx = dep; return ; } int i,j,k,p,cnt; for(i=0; i<ns; i++) { k = stk[dep][i]; cnt = 0; if(dep + n - k <= mx) return ; if(dep + dp[k] <= mx) return ; for(j=i+1; j<ns; j++) { p = stk[dep][j]; if(g[k][p]) stk[dep+1][cnt++] = p; } dfs(n, cnt, dep+1); } return ; } int clique(int n) { int i,j,ns; for(mx=0, i=n-1; i>=0; i--) { for(ns=0, j=i+1; j<n; j++) if(g[i][j]) stk[1][ns++] = j; dfs(n, ns, 1); dp[i] = mx; } return mx; } int x[maxn],y[maxn],n,k; double arc[maxn][maxn],dis[maxn*maxn]; bool check(double lim) { int i,j; memset(g,0,sizeof(g)); for(int i=0; i<n; i++) for(int j=i+1; j<n; j++) if(arc[i][j] >= lim) g[i][j] = g[j][i] = 1; if(clique(n) >= k) return true; else return false; } int main() { int i,j,cnt; while(scanf("%d%d",&n,&k)!=EOF) { for(i=0; i<n; i++) scanf("%d%d",&x[i],&y[i]); cnt=0; for(i=0; i<n; i++) { arc[i][i] = -1; for(j=i+1; j<n; j++) { arc[i][j] = sqrt((double)((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]))); dis[cnt++] = arc[j][i] = arc[i][j]; } } sort(dis,dis+cnt); int l=0,r=cnt-1,mid,ans; while(l<=r) { mid = (l+r)>>1; if(check(dis[mid])) { ans = mid; l = mid+1; } else r = mid-1; } printf("%.2lf\n",dis[ans]); } return 0; }