[HDU3622]Bomb Game(2-SAT)

来源:互联网 发布:伊斯兰 知乎 编辑:程序博客网 时间:2024/05/22 04:50

题目描述

传送门

题解

最小值最大,二分答案(实数)
判定?
二分出答案mid之后相当于是有一些点不能同时选(距离<mid)
同时每一组两个点必须选一个
就是一个经典的2-SAT问题
我们只需要判断是否有解即可
假设A1,B2不能同时选,那么如果选A1的话,B1是必选的
同样地,如果选B2,那么A2必选
那么连边A1->B1,B2->A2
用tarjan求强连通分量
如果某一组的两个点在同一个强连通分量里,则无解
因为p能到达的点是选p则必选的点

代码

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 505const double eps=1e-9;int dcmp(double x){    if (x<=eps&&x>=-eps) return 0;    return (x>0)?1:-1;}struct Point{    double x,y;    Point (double X=0,double Y=0)    {        x=X,y=Y;    }};int n,cnt,dfs_clock,top,scc;double x,y,ans;Point p[N*2];int tot,point[N*2],nxt[N*N*10],v[N*N*10];int dfn[N*2],low[N*2],vis[N*2],stack[N*2],belong[N*2];double Dis(Point P,Point Q){    double x=P.x-Q.x,y=P.y-Q.y;    return sqrt(x*x+y*y);}void add(int x,int y){    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;}void tarjan(int x){    dfn[x]=low[x]=++dfs_clock;stack[++top]=x;vis[x]=1;    for (int i=point[x];i;i=nxt[i])        if (!dfn[v[i]])        {            tarjan(v[i]);            low[x]=min(low[x],low[v[i]]);        }        else if (vis[v[i]])            low[x]=min(low[x],dfn[v[i]]);    if (dfn[x]==low[x])    {        int now=0;++scc;        while (now!=x)        {            now=stack[top--];            belong[now]=scc;            vis[now]=0;        }    }}bool check(double mid){    tot=0;memset(point,0,sizeof(point));    for (int i=0;i<=cnt;++i)        for (int j=i+1;j<=cnt;++j)            if (dcmp(Dis(p[i],p[j])-mid)<0)            {                add(i+1,(j^1)+1);                add(j+1,(i^1)+1);            }    memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));    memset(belong,0,sizeof(belong));dfs_clock=top=scc=0;    for (int i=1;i<=cnt+1;++i)        if (!dfn[i]) tarjan(i);    for (int i=0;i<=cnt;i+=2)        if (belong[i+1]==belong[(i^1)+1])            return false;    return true;}double find(){    double l=0.0,r=20000.0,mid,ans=0.0;    while (dcmp(r-l)!=0)    {        mid=(l+r)/2;        if (check(mid)) ans=l=mid;        else r=mid;    }    return ans;}int main(){    while (~scanf("%d",&n))    {        cnt=-1;        for (int i=1;i<=n;++i)        {            scanf("%lf%lf",&x,&y);            p[++cnt]=Point(x,y);            scanf("%lf%lf",&x,&y);            p[++cnt]=Point(x,y);        }        ans=find();        printf("%.2lf\n",ans/2);    }}
0 0
原创粉丝点击