就是dancing links 求最小支配集,重复覆盖
精确覆盖时:每次缓存数据的时候,既删除行又删除列(这里的删除列,只是删除表头)
重复覆盖的时候:只删除列,因为可以重复覆盖
然后重复覆盖有一个估价函数,这个函数很强大,可以进行强力剪枝
这个估价函数的意思是,搜索到当前时,至少还需要删除几行,就可以完全覆盖了
这个至少得意思是最优删:
选择一列,假设覆盖这一列的有许多行,假设这些行覆盖的所有列都是一行覆盖的,然后记录数量
然后重复操作,直到全部覆盖,所以这个数量就是最少要的数量
(估价函数很重要)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<cstdio> #include<cstring> #include<queue> #include<cstdlib> #include<algorithm> #include<vector> #include<cmath> using namespace std; typedef long long LL; const int N=3000; const double eps=1e-8; int n,m,sz,k; int u[N],l[N],r[N],d[N]; int h[55],s[55],col[N]; void init() { for(int i=0; i<=m; ++i) { s[i]=0; u[i]=d[i]=i; l[i]=i-1; r[i]=i+1; } r[m]=0; l[0]=m; sz=m; for(int i=1; i<=n; ++i) h[i]=-1; } void link(int x,int y) { ++sz; ++s[y],col[sz]=y; u[sz]=u[y],d[u[y]]=sz; d[sz]=y,u[y]=sz; if(h[x]==-1)h[x]=l[sz]=r[sz]=sz; { l[sz]=l[h[x]]; r[l[h[x]]]=sz; r[sz]=h[x]; l[h[x]]=sz; } } void del(int y) { for(int i=d[y]; i!=y; i=d[i]) r[l[i]]=r[i],l[r[i]]=l[i]; } void resume(int y) { for(int i=d[y]; i!=y; i=d[i]) r[l[i]]=l[r[i]]=i; } bool vis[55]; int f() { int ret=0; for(int i=r[0]; i; i=r[i]) vis[i]=0; for(int i=r[0]; i; i=r[i]) { if(vis[i])continue; vis[i]=1; ++ret; for(int j=d[i]; j!=i; j=d[j]) for(int k=r[j]; k!=j; k=r[k]) vis[col[k]]=1; } return ret; } bool dance(int pos) { if(pos+f()>k)return 0; if(!r[0]) { if(pos<=k)return 1; return 0; } int t=r[0]; for(int i=r[0]; i!=0; i=r[i]) if(s[i]<s[t])t=i; for(int i=d[t]; i!=t; i=d[i]) { del(i); for(int j=r[i]; j!=i; j=r[j]) del(j); if(dance(pos+1))return 1; for(int j=l[i]; j!=i; j=l[j]) resume(j); resume(i); } return 0; } struct Point { double x,y; }b[55],e[55]; double dis(int i,int j) { return sqrt((b[i].x-e[j].x)*(b[i].x-e[j].x)+(b[i].y-e[j].y)*(b[i].y-e[j].y)); } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&m,&k); swap(n,m); for(int i=1;i<=m;++i) scanf("%lf%lf",&e[i].x,&e[i].y); for(int i=1;i<=n;++i) scanf("%lf%lf",&b[i].x,&b[i].y); double low=0,high=1e6; while(high-low>=eps) { double mid=(high+low)/2.0; init(); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(dis(i,j)<=mid) link(i,j); if(dance(0))high=mid; else low=mid; } low=(high+low)/2; printf("%.6f\n",low); } return 0; }