HDU 2295 Radar【DLX+二分】

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2295
在这里插入图片描述
我来补坑啦~ 没办法, 为了得到1024勋章只好
★这题就是舞蹈链求重复覆盖问题+二分法的应用,写3天,TLE3天,最后的原因竟是n和m在某个地方用反了


翻译:

有n个城市,m个雷达,现在最多可以用k个雷达,问最少将雷达的监察范围设置为多少,能监察到所有的城市


思路:

假如监察范围是r(和代码中不同),那么我们可以得到每个雷达可以监察哪些城市。

此时联想 舞蹈链求重复覆盖的模型矩阵中选择最少的行使每一列至少有一个1

那我们接下来 可以让雷达为行、城市为列 建立十字交叉循环双向链即可 然后舞蹈链dlx.dance(0) 就可判断这个r能不能满足
如果能,那肯定往更小的找 ->这就用二分 AC 完事了~

代码

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
using namespace std;
const int maxn=3000;
const int maxm=55;
const int sz=1<<10;
const int mod=1e9+7;
const int inf=2e9;
const double eps=1e-8;
const double pi=acos(-1);
typedef long long LL;
template<class t>
inline void read(t &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    t res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
struct DLX
{
    int n,m,cnt,k;
    int up[maxn],down[maxn],left[maxn],right[maxn],col[maxn];
    int sz[maxm],head[maxm];
    bool vis[maxm];
    void init(int nn,int mm,int kk)
    {
        n=nn; m=mm; k=kk;
        for(int i=0;i<=m;i++){
            right[i]=i+1;
            left[i]=i-1;
            sz[i]=0;
            up[i]=down[i]=i;
        }
        cnt=m;
        right[m]=0; left[0]=m;
        for(int i=1;i<=n;i++) head[i]=-1;
    }
    void link(int r,int c)
    {
        cnt++;
        col[cnt]=c;
        sz[c]++;
        down[cnt]=c;
        up[cnt]=down[c];
        down[up[c]]=cnt;
        up[c]=cnt;
        if(head[r]==-1) head[r]=right[cnt]=left[cnt]=cnt;
        else{
            int tmp=head[r];
            right[cnt]=tmp;
            left[cnt]=left[tmp];
            right[left[tmp]]=cnt;
            left[tmp]=cnt;
        }
    }
    void del(int c)
    {
        for(int i=down[c];i!=c;i=down[i]){
            right[left[i]]=right[i];
            left[right[i]]=left[i];
        }
    }
    void resume(int c)
    {
        for(int i=down[c];i!=c;i=down[i]){
            left[right[i]]=right[left[i]]=i;
        }
    }
    int f()
    {
        int res=0;
        for(int c=right[0];c!=0;c=right[c]) vis[c]=1;
        for(int c=right[0];c!=0;c=right[c]){
            if(vis[c]){
                res++;
                vis[c]=0;
                for(int i=down[c];i!=c;i=down[i]){
                    for(int j=right[i];j!=i;j=right[j]){
                        vis[col[j]]=0;
                    }
                }
            }
        }
        return res;
    }
    bool dance(int dep)
    {
        if(dep+f()>k) return 0;
        if(right[0]==0) return 1;
        int now=right[0];
        for(int c=now;c!=0;c=right[c]){
            if(sz[c]<sz[now]) now=c;
        }
        for(int c=down[now];c!=now;c=down[c]){
            del(c);
            for(int i=right[c];i!=c;i=right[i]) del(i);
            if(dance(dep+1)) return 1;
            for(int i=right[c];i!=c;i=right[i]) resume(i);
            resume(c);
        }
        return 0;
    }
}dlx;
struct point
{
    double x,y;
}radar[maxm],city[maxm];
double get(point a,point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main()
{
    int n,m,k,t;
    read(t);
    while(t--){
        read(n); read(m); read(k);
        for(int i=1;i<=n;i++){
            read(city[i].x); read(city[i].y);
        }
        for(int i=1;i<=m;i++){
            read(radar[i].x); read(radar[i].y);
        }
        double l=0,r=2000;
        while(r-l>=eps){
            double mid=(l+r)/2;
            dlx.init(m,n,k);
            for(int i=1;i<=m;i++){
                for(int j=1;j<=n;j++){
                    if(mid>=get(radar[i],city[j])){
                        dlx.link(i,j);
                    }
                }
            }
            if(dlx.dance(0)) r=mid-eps;
            else l=mid+eps;
        }
        printf("%.6lf\n",l);
    }
    return 0;
}
发布了71 篇原创文章 · 获赞 89 · 访问量 8542

猜你喜欢

转载自blog.csdn.net/weixin_43890662/article/details/102734585
今日推荐