HDU 2295 Radar【舞蹈链】【可重复覆盖】

debug了好久。。

最后终于找到了错误在于给row和col的空间应该是maxnode,而我给的是maxN和maxM。orz

建模比较简单,因为比较套路,想一下列和行分别是什么就能做出来了。注意精度得是1e-8才能过。

注意还要剪一下枝,就是d+f()<=k,f()返回填满剩下列的至少行数,这是优于d<=k的可行性剪枝(因为能剪掉更多东西)。

怎么设计f()呢,right[0]这一列必须要满足,但我们不知道选哪一行最好,所以我们就把所有行都选上(因为最好的也不好于都选上),再把对应的列数消一下。然后再right看下一列,这样得到的cnt就是至少的行数。这个行数一定小于等于可行的最小需要行数。

最后简单说一下可重复覆盖的模板怎么写:

 比不可重复的模板好写。区别在于remove和resume上。我们只需要删除这一列就可以了(因为可重复覆盖)

还注意一下remove函数的参数不一定要是列标元素,可以是任何一个元素的id,remove(id)代表删除id所在的这一列的所有元素【除了id本身】。这么实现是因为好写,当然有别的实现办法。总之把它当板子用就行了,我手写了两遍dlx,以后也不打算手写了。毕竟ACM考的是建模

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<iomanip> 
#include<algorithm>
#include<vector>
#define INF 2e9
#define maxnode 3000
#define maxM 55
#define maxN 55
using namespace std;

double city1[55],city2[55],radar1[55],radar2[55];
double dist[100][100];
const double eps = 1e-8;
struct DLX{
    int n,m,k;//k为限制搜索深度 
    int up[maxnode],down[maxnode],left[maxnode],right[maxnode];
    int h[maxN],s[maxM],row[maxnode],col[maxnode];
    int id,ansd,ans[maxN];
    void init(int n1,int m1,int k1){
        n=n1; m=m1; k=k1;
        ansd=0;//无解 
        for(int i=0;i<=m;i++){
            s[i]=0;
            left[i]=i-1;
            right[i]=i+1;
            up[i] = down[i] = i;
        }
        left[0]=m; right[m]=0;
        id=m;
        for(int i=1;i<=n;i++) h[i]=-1;
    }
    
    void link(int r,int c){
        s[c]++;
        row[ ++id ] = r; col[id]=c;
        down[ up[c] ] = id;
        up[id]= up[c];
        up[c] = id;
        down[id]=c;
        if( h[r]==-1 ) h[r]=left[id]=right[id]=id;
        else{
            left[id]=left[h[r]];
            right[id]=h[r];
            right[left[h[r]]]=id;
            left[h[r]]=id;
        }
    }
    
    void remove(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]){
            right[left[i]]=i;
            left[right[i]]=i;
        }
    }
    bool v[maxM];
    int f(){//最少的选择行数,把所有列数覆盖
        int cnt=0;
        for(int c=right[0];c!=0;c=right[c]) v[c]=true;
        for(int c=right[0];c!=0;c=right[c]){
            if( v[c] ){
                v[c]=false;
                cnt++;
                for(int i=down[c];i!=c;i=down[i])
                 for(int j=right[i];j!=i;j=right[j]) {
                     v[ col[j] ]=false;
                 }
            }
        }
        return cnt;
    }
    
    bool dance(int d){
        if( d+f()>k ) return false;
        if( right[0]==0 ) return true;
        int c=right[0];
    
        for(int i=c;i!=0;i=right[i])
            if( s[i]<s[c] ) c=i;
            
        
        for(int i=down[c];i!=c;i=down[i]){
            remove(i);
            for(int j=right[i];j!=i;j=right[j]) remove(j);
            if( dance(d+1) ) return true;
            for(int j=left[i];j!=i;j=left[j]) resume(j);
            resume(i);
        }
        return false;
    }
}dlx;

int main(){
    ios::sync_with_stdio(false);
    int t; cin>>t;
    while(t--){
        //每个city是col,radar是row
        //重复覆盖
        int n,m,k; cin>>n>>m>>k;
        for(int i=1;i<=n;i++) cin>>city1[i]>>city2[i];
        for(int i=1;i<=m;i++) cin>>radar1[i]>>radar2[i];
        
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++){
                dist[i][j] = sqrt( (city1[j]-radar1[i])*(city1[j]-radar1[i]) + (city2[j]-radar2[i])*(city2[j]-radar2[i]) );
            }
                
        
        
        double start=0,end=1416;
        while( end-start>eps ){
            dlx.init(m,n,k);
            double mid=(start+end)/2;
            for(int i=1;i<=m;i++){
                for(int j=1;j<=n;j++){//can radar station i reach city j
                    if( mid>=dist[i][j] ) dlx.link(i,j);
                }
            }
            if( dlx.dance(0) ) end=mid;
            else start=mid;
        }
        cout<<fixed<<setprecision(6)<<end<<endl;
    }

    return 0;    

}

猜你喜欢

转载自www.cnblogs.com/ZhenghangHu/p/9711045.html
今日推荐