#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <functional>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include <ctime>
#pragma comment(linker, "/STACK:102400000,102400000")
typedef int ll;
#define INF 1e9
#define MAXN 10000
#define MAXM 100
const int maxn = 1000005;
//#define mod 1000000007
#define eps 1e-7
#define pi 3.1415926535897932384626433
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define scan(n) scanf("%d",&n)
#define scanll(n) scanf("%I64d",&n)
#define scan2(n,m) scanf("%d%d",&n,&m)
#define scans(s) scanf("%s",s);
#define ini(a) memset(a,0,sizeof(a))
#define out(n) printf("%d\n",n)
//ll gcd(ll a,ll b) { return b==0?a:gcd(b,a%b);}
using namespace std;
#define N 60
#define V N*N
int L[V],R[V];//记录左右方向的双向链表
int U[V],D[V];//记录上下方向的双向链表
int C[V];//指向其列指针头的地址
int H[N];//行指针头
int S[N];//记录列链表中节点的总数
int size,n,m,K,ak;
int visit[N];
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(H[r]==-1) H[r]=L[size]=R[size]=size;
else
{
L[size]=L[H[r]];R[L[H[r]]]=size;
R[size]=H[r];L[H[r]]=size;
}
size++;
}
void remove(int Size)
{
int j; //重复覆盖不删除行
for(j=D[Size];j!=Size;j=D[j])
L[R[j]]=L[j],R[L[j]]=R[j];
}
void resume(int Size)
{
int j;
for(j=D[Size];j!=Size;j=D[j])
L[R[j]]=R[L[j]]=j;
}
int h()
{
int count=0,i,j,k; //估价函数
memset(visit,0,sizeof(visit));
for(i=R[0];i;i=R[i])
{
if(visit[i]) continue;
count++;
for(j=D[i];j!=i;j=D[j])
{
for(k=R[j];k!=j;k=R[k])
visit[C[k]]=1;
}
}
return count;
}
bool Dance(int k)
{ //重复覆盖一般需要暴搜,然后用估价函数剪枝
int i,j,min,c;
if(k + h() > K || k+h() >= ak) return false; //k表示已选择的点,h()为估计至少需要的点,ak为当前答案
if(!R[0])
{
if(k<ak) ak=k;
return true;
}
for(min=N,i=R[0];i;i=R[i])
if(min>S[i]) min=S[i],c=i;
for(i=D[c];i!=c;i=D[i])
{
remove(i); //这个写里面,因为不一定删i所在的行,
for(j=R[i];j!=i;j=R[j]) //循环删除该行剩下的,总的来说就是删了整行
remove(j);
if(Dance(k+1)) return true;
for(j=R[i];j!=i;j=R[j])
resume(j);
resume(i);
}
return false;
}
void init(int n)
{
for(int i=0;i<=n;i++)
{
S[i]=0;
U[i]=D[i]=i;
L[i+1]=i;R[i]=i+1;
}R[n]=0;
size=n+1;
memset(H,-1,sizeof(H));
}
struct Point
{
int x,y;
}a[N],b[N];
int dis(Point a,Point b)
{
return (a.x-b.x) * (a.x-b.x) + (a.y-b.y) * (a.y-b.y);
}
int c[4000];
bool solve(int mid)
{
init(n);
ak = N + 1;
rep1(i,m) rep1(j,n)
{
if(dis(b[i],a[j]) <= mid) Link(i,j);
}
if(Dance(0))
return true;
return false;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
#endif
int T;
cin>>T;
while(T--)
{
cin>>n>>m>>K;
rep1(i,n) scanf("%d%d",&a[i].x,&a[i].y);
rep1(i,m) scanf("%d%d",&b[i].x,&b[i].y);
int cnt = 0;
rep1(i,m) rep1(j,n)
{
c[cnt++] = dis(b[i],a[j]);
}
sort(c,c+cnt);
cnt = unique(c,c+cnt) - c;
int l = 0, r = cnt - 1;
while(l < r)
{
int mid = (l + r) / 2;
if(solve(c[mid])) r = mid;
else l = mid + 1;
}
printf("%.6lf\n",sqrt(c[l] * 1.0));
}
return 0;
}
hdu 2295 DLX重复覆盖
最新推荐文章于 2020-01-31 22:27:07 发布