hdu2295 Radar 二分+DLX重复覆盖+A*

      N个城市,M个雷达站,最多可开K个雷达工作,给出城市和雷达的坐标,问雷达的工作半径最少为多少可以满足要求?

直接二分距离,判断当前距离K个雷达站是否能覆盖全部城市,判断的时候可以用DLX来搜,建立M行*N列的01矩阵,行表示雷达站,列表示城市,由于允许多个雷达站覆盖一个城市的情况,所以这题跟精确覆盖的实现还不太一样,remove和resume要改一下。另外这题裸上还会TLE,所以在搜索的时候要加个A*剪枝,估价函数的含义大致就是在当前的状态下,最少需要多少行才有可能覆盖所有的城市(注意这个数只是个下界,不是确定的值),那么若当前启动的雷达数+估价超过了限制的话,就可以剪掉了...

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxr=55;
const int maxc=55;
const int maxn=maxr*maxc;
const int inf=(1<<28);
int col[maxn],row[maxn],ans[maxn];
int S[maxc],H[maxr];
int size,cnt;
int U[maxn],D[maxn],L[maxn],R[maxn];
int g[maxr][maxc];
struct PT
{
    double x,y;
}city[55],radar[55];

int n,m,k;

struct DLX
{
    int h()
    {
        bool hs[55];
        memset(hs,0,sizeof hs);
        int ret=0;
        for (int i=R[0]; i!=0; i=R[i])
        {
            if (!hs[i])
            {
                ret++;
                hs[i]=true;
                for (int j1=D[i]; j1!=i; j1=D[j1])
                 for (int j2=R[j1]; j2!=j1; j2=R[j2])
                 hs[col[j2]]=true;
            }
        }
        return ret;
    }
    void remove(int c)
    {
        for (int i=D[c]; i!=c; i=D[i])
         {
             L[R[i]]=L[i];
             R[L[i]]=R[i];
         }
    }
    void resume(int c)
    {

        for (int i=U[c]; i!=c; i=U[i])
         {
             L[R[i]]=i;
             R[L[i]]=i;
         }
    }
    bool dfs(int p)
    {
        if (p+h()>k) return false;
        if (p>k) return false;
        int c=R[0];
        if (c==0)
        {
            cnt=p;
            return true;
        }
        for (int i=R[0]; i!=0; i=R[i])
        if (S[i]<S[c]) c=i;

        for (int i=D[c]; i!=c; i=D[i])
        {
            remove(i);
            for (int j=R[i]; j!=i; j=R[j]) remove(j);
            if (dfs(p+1)) return true;
            for (int j=L[i]; j!=i; j=L[j]) resume(j);
            resume(i);
        }
        return false;
    }
    void init(int m)
    {
        for (int i=0; i<=m; i++)
        {
            S[i]=0;
            R[i]=i+1;
            L[i]=i-1;
            U[i]=D[i]=i;
        }
        L[0]=m;
        R[m]=0;
        size=m+1;
        memset(H,-1,sizeof H);
    }
    void link(int x,int y)
    {
        ++S[col[size]=y];
        row[size]=x;
        D[size]=D[y];
        U[D[y]]=size;
        U[size]=y;
        D[y]=size;

        if (H[x]<0) H[x]=L[size]=R[size]=size;
        else
        {
            R[size]=R[H[x]];
            L[R[H[x]]]=size;
            L[size]=H[x];
            R[H[x]]=size;
        }
        size++;
    }
}dlx;

double dis(PT p, PT q)
{
    return sqrt((double)((p.x-q.x)*(p.x-q.x)+(p.y-q.y)*(p.y-q.y)));
}
void init(double limit)
{
    memset(g,false,sizeof g);
    for (int i=1; i<=m; i++)
     for (int j=1; j<=n; j++)
     if (dis(radar[i],city[j])<=limit) g[i][j]=true;
}
int main()
{
//    freopen("in.txt","r",stdin);
    int tt;
    scanf("%d",&tt);
    while (tt--)
    {
        scanf("%d%d%d",&n,&m,&k);
        for (int i=1; i<=n; i++)
        scanf("%lf%lf",&city[i].x,&city[i].y);
        for (int i=1; i<=m; i++)
        scanf("%lf%lf",&radar[i].x,&radar[i].y);

        double l=0.0,r=sqrt(1000.0*1000.0*2.0);
        double mid;
        while(fabs(l-r)>1e-8)
        {
            mid=(l+r)/2.0;
            init(mid);
            dlx.init(n);
            for (int i=1; i<=m; i++)
             for (int j=1; j<=n; j++)
             if (g[i][j]) dlx.link(i,j);
            cnt=inf;
            if (dlx.dfs(0)) r=mid;
            else l=mid;
        }
        printf("%.6lf\n",l);

    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值