zoukankan      html  css  js  c++  java
  • hdu3656Fire station(DLX重复覆盖 + 二分)

    题目请戳这里

    题目大意:一个城市n个点,现在要建m个消防站,消防站建在给定的n个点中。求建m个消防站后,m个消防站要覆盖所有的n个点的覆盖半径最小。

    题目分析:重复覆盖问题,DLX解决。不过要求覆盖半径最小,需要二分。虽然给的范围并不大,DLX毕竟还是暴力搜索,而且精度有6位小数,因此直接二分距离的话会TLE!解决方案是将图中任意2点的距离记录下来,去重后二分已知的距离。因为消防站建在给定的n个点中,那么最小覆盖半径一定在任意2点距离中产生。

    DLX搜索的时候,一般习惯删除的时候从左往右,不过效率却不一定高。比如这题,从左向右删除和从右向左删除,跑的时间至少差了1s以上!可见用dancing links搜索的时候姿势还是很重要的。有时候换个姿势也许效率更高~

    详情请见代码:

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int N = 51;
    const int M = 30001;
    const double eps = 1e-7;
    
    double dis[N][N];
    double tle[M];
    int s[M],h[M],u[M],d[M],l[M],r[M],col[M],row[M];
    int point[N][2];
    int m,n,num,len;
    int fs;
    double getdis(int i,int j)
    {
        return sqrt((double)(point[i][0] - point[j][0])*(point[i][0] - point[j][0])
                   +(double)(point[i][1] - point[j][1])*(point[i][1] - point[j][1]));
    }
    void read()
    {
        scanf("%d%d",&n,&m);
        int i,j;
        len = 1;
        tle[len ++] = 0;
        for(i = 1;i <= n;i ++)
        {
            dis[i][i] = 0.0;
            scanf("%d%d",&point[i][0],&point[i][1]);
            for(j = 1;j < i;j ++)
                dis[i][j] = dis[j][i] = getdis(i,j),tle[len ++] = dis[i][j];
        }
    }
    void init()
    {
        memset(h,0,sizeof(h));
        memset(s,0,sizeof(s));
        for(int i = 0;i <= n;i ++)
        {
            u[i] = d[i] = i;
            l[i] = (i + n) % (n + 1);
            r[i] = (i + 1) % (n + 1);
        }
        num = n + 1;
    }
    void add(int i,int j)
    {
        if(h[i])
        {
            r[num] = h[i];
            l[num] = l[h[i]];
            r[l[num]] = l[r[num]] = num;
        }
        else
            h[i] = l[num] = r[num] = num;
        s[j] ++;
        u[num] = u[j];
        d[num] = j;
        d[u[num]] = num;
        u[j] = num;
        col[num] = j;
        row[num] = i;
        num ++;
    }
    void build(double md)
    {
        int i,j;
        init();
        for(i = 1;i <= n;i ++)
            for(j = 1;j <= n;j ++)
                if(md - dis[i][j] > -eps)
                    add(i,j);
    }
    void remove(int c)
    {
        for(int i = d[c];i != c;i = d[i])
            l[r[i]] = l[i],r[l[i]] = r[i],s[col[i]] --;
    }
    void resume(int c)
    {
        for(int i = u[c];i != c;i = u[i])
            l[r[i]] = r[l[i]] = i,s[col[i]] ++;
    }
    int A()
    {
        int i,j,k,ret = 0;
        bool vis[N];
        memset(vis,false,sizeof(vis));
        for(i = l[0];i;i = l[i])
        {
            if(vis[i] == false)
            {
                vis[i] = true;
                ret ++;
                for(j = d[i];j != i;j = d[j])
                    for(k = r[j];k != j;k = r[k])
                        vis[col[k]] = true;
            }
        }
        return ret;
    }
    void dfs(int k)
    {
        if(k + A() >= fs)
            return;
        int i,j;
        if(!r[0])
        {
            fs = min(fs,k);
            return;
        }
        int mn = 1000000;
        int c;
        for(i = l[0];i;i = l[i])
        {
            if(mn > s[i])
            {
                mn = s[i];
                c = i;
            }
        }
        for(i = d[c];i != c;i = d[i])
        {
            remove(i);
            for(j = l[i];j != i;j = l[j])
            {
                remove(j);
            }
            dfs(k + 1);
            for(j = r[i];j != i;j = r[j])
            {
                resume(j);
            }
            resume(i);
        }
    }
    void solve()
    {
        int la,ra,mid,ans;
        sort(tle + 1,tle + len);
        int i = len;
        int j;
        len = 2;
        for(j = 2;j < i;j ++)
            if(fabs(tle[j] - tle[j - 1]) > eps)
                tle[len ++] = tle[j];
        len --;
        la = 1;ra = len;
        while(la <= ra)
        {
            mid = (la + ra)>>1;
            build(tle[mid]);
            fs = M;
            dfs(0);
            if(fs <= m)
            {
                ans = mid;
                ra = mid - 1;
            }
            else
                la = mid + 1;
        }
        printf("%f
    ",tle[ans]);
    }
    int main()
    {
        int _;
        scanf("%d",&_);
        while(_ --)
        {
            read();
            solve();
        }
        return 0;
    }
    //1953MS  636K
    


  • 相关阅读:
    Apache 常用伪静态配置
    Nginx 常用伪静态配置
    数组的完全随机排列
    PHP获得IP地址
    百度编辑器ueditor代码高亮效果前台不显示的解决方法
    ckeditor 图片上传功能配置
    sendmail 邮件服务器搭建
    关于MYSQL Incorrect string value
    linux 常见命令
    zend framework 初识
  • 原文地址:https://www.cnblogs.com/riskyer/p/3353234.html
Copyright © 2011-2022 走看看