HDU 3622 2-SAT

第一道2-SAT

题意:有N对点,给出N对点的坐标,要求找出一个最大的半径R,使得可以从每对点中选择一个点,并且这N个点以自己为圆心,半径为R的圆两两不相交。

对于2*N个点,如果两个点之间“矛盾”,即两个圆相交,就连一条边。意思是:我选了这个点之后,无法选另外一组的某个点,就只能选某个点的兄弟点。对这个图求强连通分量,然后看是否有某对点属于同一个强连通分量。如果N对点每一对都属于不同的强连通分量,满足。否则不满足。然后二分答案即可。

#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <map>
#include <vector>
using namespace std;
const double eps=1e-4;
struct point
{
    int x;
    int y;
}a[210];
double dis(point a,point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
const int MAXN=210;
struct node
{
    int v;
    int nxt;
};
node edge[MAXN*MAXN];//边数
int head[MAXN];
int n,m;
int Stop,Bcnt,Dindex;//栈头,强通块数,时间戳
int DFN[MAXN],LOW[MAXN];//首时间戳,最近回溯点(根)
int Stap[MAXN];//答案栈
int instack[MAXN];//是否在栈中
int Belong[MAXN];//这个点属于第几个强连通块(点)
int cnt=0;
void add_edge(int u,int v)
{
    edge[cnt].v=v;
    edge[cnt].nxt=head[u];
    head[u]=cnt;
    cnt++;
}
void tarjan(int i)
{
    int j;
    DFN[i]=LOW[i]=++Dindex;
    instack[i]=1;
    Stap[++Stop]=i;
    for (int e=head[i]; e!=-1; e=edge[e].nxt)
    {
        j=edge[e].v;
        if (!DFN[j])//儿子没遍历
        {
            tarjan(j);//遍历
            if (LOW[j]<LOW[i])//如果儿子已经形成环
                LOW[i]=LOW[j];//父亲也要在回溯的时候进入环
        }
        else if (instack[j]&&DFN[j]<LOW[i])//邻接的在栈里,所以是大大
            LOW[i]=DFN[j];//把这个点归到大大那
    }
    if (DFN[i]==LOW[i])//这个点的根是自己
    {
        Bcnt++;//多了一个强连通分量
        do
        {
            j=Stap[Stop--];//退栈
            instack[j]=0;//标记
            Belong[j]=Bcnt;//标记
        }
        while (j!=i);
    }
}
int solve()
{
    int i;
    Stop=Bcnt=Dindex=0;//栈头,强通块数,时间戳
    memset(DFN,0,sizeof(DFN));
    for (int i=0; i<2*n; i++)
    {
//        printf ("dfn[i]\%d\n",DFN[i]);
        if (!DFN[i])
            tarjan(i);
    }
    for (int i=0;i<2*n;i+=2)//不在一个联通块里
    {
        if (Belong[i]==Belong[i+1]) return 0;
    }
    return 1;
}
int main()
{
    while (scanf ("%d",&n)!=EOF)
    {
        for (int i=0;i<2*n;i+=2)
        {
            scanf ("%d%d",&a[i].x,&a[i].y);
            scanf ("%d%d",&a[i+1].x,&a[i+1].y);
        }
        double r=40001,l=0;
        while (r-l>eps)
        {
            double mid=(l+r)/2.0;
            memset(head,-1,sizeof(head));
            cnt=0;
            for (int i=0;i<2*n;i++)
            {
                for (int j=i+1;j<2*n;j++)
                {
                    if ((i!=(j^1))&&(dis(a[i],a[j])<2*mid))
                    {
                        add_edge(i,j^1);
                        add_edge(j,i^1);
                    }
                }
            }
            if (solve())
            {
                l=mid;
            }
            else r=mid;
        }
        printf ("%.2f\n",l);
    }
    return 0;
}

 

posted on 2016-07-29 14:54  very_czy  阅读(204)  评论(0)    收藏  举报

导航