HDU 2295 Radar舞蹈链可重复覆盖
Posted zhenghanghu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}
以上是关于HDU 2295 Radar舞蹈链可重复覆盖的主要内容,如果未能解决你的问题,请参考以下文章