Hdu 2295 (二分+重复覆盖问题 Dancing Links)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2295

 

题意:给出一些城市及一些雷达的坐标,要求从这些雷达中选取最多k个能够覆盖所有的城市,问雷达的最小覆盖半径为多少。

 

二分半径,则可转化为一个判定问题,即给定雷达的覆盖半径,问从这些雷达中最多选取k个,是否能够覆盖所有这些城市。、

 

这里用到了Dancing Links 解决重复覆盖问题的方法来进行判断,与精确覆盖问题的不同之处在于,Remove中只删除当前列,而不是把所有与之相关的行及列全部删去,用

Resume恢复即可,另,由于种类型题目的限制,Dancing Links的效率不高,需要在搜索中加上启发式判断,于是就有了另一个函数的 h() 设计,使效率大为提高。

 

 Code:

 

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

typedef struct{
	double x,y;
}Point;
#define M 64
const int head=0;
const int V=M*M;
const double eps=1e-7;

int R[V],L[V],U[V],D[V],C[V];
int S[V],H[V],size;

int n,m;
int Limit;

Point radar[M];
Point city[M];

double Dis2(Point p,Point q)
{
	p.x-=q.x;p.y-=q.y;
	return p.x*p.x+p.y*p.y;
}
void Remove(int c)
{
	int i;//只删除该列
	for(i=D[c];i!=c;i=D[i])
		L[R[i]]=L[i],R[L[i]]=R[i];
}
void Resume(int c)
{
	int i;
	for(i=U[c];i!=c;i=U[i])
		L[R[i]]=R[L[i]]=i;
}
int h()
{
	int r=0,i,j,k;
	int hash[M];
	memset(hash,0,sizeof(hash));
	for(i=R[head];i!=head;i=R[i]){
		if(!hash[i]){ 
			r++;
			hash[i]=1;
			for(j=D[i];j!=i;j=D[j]){
				for(k=R[j];k!=j;k=R[k])
					hash[C[k]]=1;
			}
		}
	}
	return r;
}
int Dance(int k)
{
	int i,j,min,c;
	if(k+h()>Limit) return 0;
	if(R[head]==head)return 1;
	
	for(i=R[head],c=0,min=M;i!=head;i=R[i]){
		if(S[i]<min) min=S[i],c=i;
	}
	
	for(i=D[c];i!=c;i=D[i]){
		Remove(i);
		for(j=R[i];j!=i;j=R[j])
			Remove(j);
		if(Dance(k+1)) return 1;
		for(j=L[i];j!=i;j=L[j])
			Resume(j);
		Resume(i);
	}
	return 0;
}
void Link(int &r,int c)
{
	S[c]++;C[size]=c;
	U[size]=U[c];D[U[c]]=size;
	D[size]=c;U[c]=size;
	if(r==-1) 
		L[size]=R[size]=r=size;
	else{
		L[size]=L[r];R[L[r]]=size;
		R[size]=r;L[r]=size;
	}size++;
}

int Solve(double rr)
{
	int i,j;
	
	for(i=0;i<=n;i++){
		S[i]=0;U[i]=D[i]=i;
		R[i]=i+1;L[i+1]=i;
	}R[n]=0;
	size=n+1;
	memset(H,-1,sizeof(H));
	for(i=0;i<m;i++){
		for(j=0;j<n;j++){
			if(Dis2(radar[i],city[j])<=rr)
				Link(H[i],j+1);
		}
	}
	for(i=1;i<=n;i++){
		if(S[i]==0)
			return 0;
	}
	
	return Dance(0);
}

int main()
{
	
	int t,i;
	double up,low,mid;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d",&n,&m,&Limit);
		for(i=0;i<n;i++) 
			scanf("%lf%lf",&city[i].x,&city[i].y);
		for(i=0;i<m;i++) 
			scanf("%lf%lf",&radar[i].x,&radar[i].y);
		low=0.000001;up=1416.0;
		while(low+eps<up){
			mid=(low+up)*0.5;
			if(Solve(mid*mid))
				up=mid;
			else low=mid;
		}
		printf("%lf\n",up);
	}
	return 0;
}

你可能感兴趣的:(c,struct,ini,UP)