题意:给你n个点,然后你可以从里面找出k个点,然后使得k个点中的最短距离最大。
想法:直接二分枚举最大距离,然后把满足的边找出来,然后就看看这些点的最大独立点集,如果个数>=k,那么显然长度可能可以更长一些,所以继续枚举,如果<k,那么缩短长度以便于增加点边的个数,来得到更大的点集。这里的最大团用到了dp优化。
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; const int nodes=55; int n,k; int x[nodes],y[nodes]; bool map[nodes][nodes]; int mx,dp[nodes],stk[nodes][nodes]; double dis[nodes][nodes],l[nodes*nodes]; double Dis(int a,int b,int c,int d) { int x=a-c; int y=b-d; return sqrt(x*x*1.0+y*y*1.0); } int dfs(int ns,int dep) { if(ns==0) { if(dep>mx) mx=dep; return 1; } for(int i=0;i<ns;i++) { int u=stk[dep][i]; if(dep+n-u+1<=mx) return 0; if(dep+dp[u]<=mx) return 0; int cnt=0; for(int j=i+1;j<ns;j++) { int v=stk[dep][j]; if(map[u][v]) { stk[dep+1][cnt++]=v; } } dfs(cnt,dep+1); } return 0; } int cal(int mid) { memset(map,false,sizeof(map)); for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { if(dis[i][j]>=l[mid]) { map[i][j]=map[j][i]=true; } } } mx=0; int ns; for(int i=n;i>=1;i--) { ns=0; for(int j=i+1;j<=n;j++) { if(map[i][j]) { stk[1][ns++]=j; } } dfs(ns,1); dp[i]=mx; if(mx>=k) return 1; } return 0; } int main() { while(~scanf("%d%d",&n,&k)) { for(int i=1;i<=n;i++) { scanf("%d%d",&x[i],&y[i]); } int nn=0; for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { dis[j][i]=dis[i][j]=Dis(x[i],y[i],x[j],y[j]); l[++nn]=dis[i][j]; } dis[i][i]=0; } sort(l+1,l+nn+1); int lft=1,rht=nn,ans=1; while(lft<=rht) { int mid=(lft+rht)/2; if(cal(mid)) { ans=mid; lft=mid+1; } else rht=mid-1; } printf("%.2lf\n",l[ans]); } return 0; }