hdu 2295 DLX+二分

把城市看做列,把雷达看成是行。

那么就是要求最少的行覆盖所有的列,并且可以重复覆盖。所以就发现了DLX的重复覆盖的身影~

至于半径就是二分了~

代码如下:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cstring>
#include <math.h>
#include <stdlib.h>
using namespace std;
const int maxnode = 55*55;
const int MaxM = 60;
const int MaxN = 60;
int N,M,K;
struct DLX
{
	int n,m,size;
	int U[maxnode],D[maxnode],R[maxnode],L[maxnode],Row[maxnode],Col[maxnode];
	int H[MaxN],S[MaxM];
	int ands,ans[MaxN];
	void init(int _n,int _m)
	{
		n = _n;
		m = _m;
		for(int i = 0;i <= m;i++)
		{
			S[i] = 0;
			U[i] = D[i] = i;
			L[i] = i-1;
			R[i] = i+1;
		}
		R[m] = 0; L[0] = m;
		size = m;
		for(int i = 1;i <= n;i++)
			H[i] = -1;
	}
	void Link(int r,int c)
	{
		++S[Col[++size]=c];
		Row[size] = r;
		D[size] = D[c];
		U[D[c]] = size;
		U[size] = c;
		D[c] = size;
		if(H[r] < 0)H[r] = L[size] = R[size] = size;
		else
		{
			R[size] = R[H[r]];
			L[R[H[r]]] = size;
			L[size] = H[r];
			R[H[r]] = size;
		}
	}
	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]]=R[L[i]]=i;
	}
	bool v[maxnode];
	int f()
	{
		int ret = 0;
		for(int c = R[0];c != 0;c = R[c])v[c] = true;
		for(int c = R[0];c != 0;c = R[c])
			if(v[c])
			{
				ret++;
				v[c] = false;
				for(int i = D[c];i != c;i = D[i])
					for(int j = R[i];j != i;j = R[j])
						v[Col[j]] = false;
			}
		return ret;

	}
	bool Dance(int d)
	{
		if(d + f() > K)return false;
		if(R[0] == 0)return d <= K;
		int c = R[0];
		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(Dance(d+1))return true;
			for(int j = L[i];j != i;j = L[j])resume(j);
			resume(i);
		}
		return false;
	}
};
DLX g;
double eps=1e-8;
struct Point
{
	int x,y;
	void input()
	{
		scanf("%d%d",&x,&y);
	}
}city[MaxM],sta[MaxN];
int Dis[MaxN][MaxM];
int dis(Point a,Point b)
{
    int tempx=a.x-b.x;
    int tempy=a.y-b.y;
	return tempx*tempx+tempy*tempy;
}
void cal_dis()
{
    int i,j;
    for(i=1;i<=M;i++)
    {
        for(j=1;j<=N;j++)
        {
            Dis[i][j]=dis(sta[i],city[j]);
        }
    }
}
int main()
{
    //freopen("E.in","r",stdin);
    //freopen("E.out","w",stdout);
    int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d%d",&N,&M,&K);
		for(int i = 1;i <=N;i++){
			city[i].input();
		}
		for(int i=1;i<=M;i++)
        {
            sta[i].input();
        }
        cal_dis();
		double l = 0.0, r = 2000.0;
		double ans = 0.0;
		while(l <= r&&(r-l)>eps)
		{
			double mid = (l+r)/2;
			g.init(M,N);
			for(int i = 1;i <=M;i++)
				for(int j =1;j <=N;j++)
					if(Dis[i][j] <= mid*mid)
						g.Link(i,j);
			if(g.Dance(0)){r = mid-eps;ans = mid;}
			else l = mid+eps;
		}
		printf("%.6lf\n",ans);
	}
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值