[hdu-3622] Bomb Game题解

来源:互联网 发布:淘宝怎么追加差评 编辑:程序博客网 时间:2024/06/05 22:40

题目传送门
题意解析:这题就是给了你n组点,每组有两个点,每个点都有一个坐标,然后每组中选择一个点,然后给以你选择的点为圆心的点找共同的一个半径,使每两个圆没有公共区域(也就是互不相交),让你找出最大的半径(hdu上说是最小半径,应该是题目出问题了)。


My opinion:因为当时刚刚讲完2-sat问题,做的题就呵呵了。而且这每两个点去一个点,还有约束条件,实在太明显了。但是在你不知道半径的情况下该如何判断这两个点是否矛盾呢?有句话说得好,有条件要上,没有条件创造条件也要上。于是我们就去创造条件,因为坐标大小在[-10000,10000],所以在极限的情况下,半径大小为绝对不到40000(反正n才100,二分还是lg级的,草率点没关系)。
至于如何判断两个圆是否矛盾,只要两个圆的圆心之间的距离大于半径之和就有公共区域。
总结:
1、输入后二分答案。
2、对于每个mid,建一次图。
3、对于每次的图做一遍2-sat
(对了,因为要保留两位小数,所以精度很有问题,eps=1e-5够了,更大也可以,总之不能1e-3以上)


贼长的代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath> #include<vector>#define rep(i,a,n) for (int i=a;i<=n;i++)#define per(i,a,n) for (int i=a;i>=n;i--)#define Clear(a,x) memset(a,x,sizeof(a))#define sqr(x) (x)*(x)#define ll long long#define db double#define INF 2000000000#define eps 1e-5using namespace std;int read(){    int x=0,f=1;    char ch=getchar();    while (ch<'0'||ch>'9') f=ch=='-'?-1:f,ch=getchar();    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();    return x*f;}const int maxn=205,maxm=40005;struct edge{    int next,v;}E_1[maxm],E_2[maxm];struct node{    int x,y;}a[maxn<<1];int head_1[maxn],head_2[maxn];bool flag1[maxn],flag2[maxn];int c[maxn],belong[maxn];int len,num1,num2,n;void init(){    Clear(head_1,-1);    Clear(head_2,-1);    Clear(flag1,0);    Clear(flag2,0);    len=0;    num1=num2=0;}db calc(node a1,node a2){    return sqrt((db)sqr(a1.x-a2.x)+(db)sqr(a1.y-a2.y));}void add(int u,int v){    E_1[++len].v=v;    E_1[len].next=head_1[u];    head_1[u]=len;    E_2[len].v=u;    E_2[len].next=head_2[v];    head_2[v]=len;}void solve(db mid){    rep(i,0,n*2-3){        int t;        if (i%2==0) t=i+2;            else t=i+1;        rep(j,t,2*n-1)            if (calc(a[i],a[j])<2*mid){                add(i,j^1);                add(j,i^1);            }    }}void dfs1(int u){    flag1[u]=1;    for (int e=head_1[u];e!=-1;e=E_1[e].next){        int v=E_1[e].v;        if (!flag1[v])            dfs1(v);    }    c[++num1]=u;}void dfs2(int u){    flag2[u]=1;    belong[u]=num2;    for (int e=head_2[u];e!=-1;e=E_2[e].next){        int v=E_2[e].v;        if (!flag2[v])            dfs2(v);    }}bool ok(int n){    rep(i,0,n*2-1)        if (!flag1[i])         dfs1(i);    per(i,num1,1)        if (!flag2[c[i]]){            dfs2(c[i]);            num2++;                }    for (int i=0;i<=2*n-2;i+=2)        if (belong[i]==belong[i+1]) return false;    return true;}int main(){    while (~scanf("%d",&n)){        rep(i,0,n-1){            a[i*2].x=read();            a[i*2].y=read();            a[i*2+1].x=read();            a[i*2+1].y=read();        }        db l=0,r=maxm;        while (r-l>=eps){            db mid=(l+r)/2;             init();            solve(mid);            if (ok(n)) l=mid;                else r=mid;        }        printf("%.2lf\n",r);    }    return 0;}
原创粉丝点击