POJ2296 Map Labeler【2-SAT】【二分】

题目链接:

http://poj.org/problem?id=2296

题目大意:

制作地图是一件很复杂的工作,其中一项任务就是为地图上的城市制作标示——在地图上每个

城市的所在位置附近贴上一个文字标签。标签的一个要求就是亮亮不能重叠。本题中,假设每

个城市都是平面上的一个点,坐标为(x,y),他的标签是一个平行于xy轴的正方形,现在要求

代表每个城市的点处于正方形标签的顶边正中央或是底边正中央,如下图所示。对于一个好的

地图,所有的标签大小都应该相同,并且任意两个标签之间没有重叠,但是可以有公共边。

那么问题来了:给定所有城市在平面上的坐标(全部为整数),计算出符合上述要求的标签的最

大尺寸。

思路:

先考虑简单的问题。如果给定一个尺寸,如何来判断是否存在这样一种方案满足上边的要求。

对于每个城市来说,贴标签有两种选择,一种是在标签顶边正中间贴,另一种是在标签底边正

中间贴。可以将每个城市拆分成两个点i和i+N,分别表示两种选择。而这两种选择只能存在一

个,在一种方案中不能同时存在,那么问题就变为了2-SAT问题。通过Tarjan求强连通分量+缩

点就可以解决。

那么再来考虑尺寸问题。给的尺寸越小,方案就越可能实现。可以判断出:所求的最大尺寸肯

定在范围0~INF之间。那么用二分法就可以很方便的求出这个值。那么判断两个正方形相交就

通过判断两个正方形中心点的水平距离和竖直距离是否都小于它们的边长,就可以确定两个正

方形的相交关系。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
const int MAXN = 220;
const int MAXM = MAXN*MAXN;
const int INF = 0xffffff0;

struct NODE
{
    int x,y;
}Node[MAXN];

struct EdgeNode
{
    int to;
    int next;
}Edges[MAXM];

int Head[MAXN],vis[MAXN];
int low[MAXN],dfn[MAXN],belong[MAXN],Stack[MAXN];
int m,id,lay,scc,N;

void AddEdges(int u,int v)
{
    Edges[id].to = v;
    Edges[id].next = Head[u];
    Head[u] = id++;
}

void TarBFS(int pos)
{
    dfn[pos] = low[pos] = ++lay;
    Stack[m++] = pos;
    vis[pos] = 1;

    for(int i = Head[pos]; i != -1; i = Edges[i].next)
    {
        int v = Edges[i].to;
        if( !dfn[v] )
        {
            TarBFS(v);
            low[pos] = min(low[pos],low[v]);
        }
        else if(vis[v])
            low[pos] = min(low[pos],low[v]);
    }
    int v;
    if(dfn[pos] == low[pos])
    {
        ++scc;
        do
        {
            v = Stack[--m];
            belong[v] = scc;
            vis[v] = 0;
        }while(v != pos);
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&N);
        for(int i = 0; i < N; ++i)
            scanf("%d%d",&Node[i].x,&Node[i].y);

        int Left = 0, Right = INF, mid;
        int ans = -1;
        while(Left <= Right)
        {
            mid = (Left + Right) >> 1;
            memset(low,0,sizeof(low));
            memset(dfn,0,sizeof(dfn));
            memset(vis,0,sizeof(vis));
            memset(Head,-1,sizeof(Head));
            memset(belong,0,sizeof(belong));
            id = m = lay = scc = 0;
            for(int i = 0; i < N; ++i)
            {
                for(int j = 0; j < N; ++j)
                {
                    if(i != j && abs(Node[i].x-Node[j].x) < mid)
                    {
                        if(Node[i].y == Node[j].y)
                        {
                            AddEdges(i,j+N);
                            AddEdges(j,i+N);
                            AddEdges(j+N,i);
                            AddEdges(i+N,j);
                        }
                        else if(Node[i].y > Node[j].y && Node[i].y - Node[j].y < mid)
                        {
                            AddEdges(i,i+N);
                            AddEdges(j+N,j);
                        }
                        else if(Node[i].y < Node[j].y && Node[j].y - Node[i].y < mid)
                        {
                            AddEdges(j,j+N);
                            AddEdges(i+N,i);
                        }
                        else if(Node[i].y > Node[j].y && Node[i].y - Node[j].y < 2*mid)
                        {
                            AddEdges(i,j);
                            AddEdges(j+N,i+N);
                        }
                        else if(Node[i].y < Node[j].y && Node[j].y - Node[i].y < 2*mid)
                        {
                            AddEdges(j,i);
                            AddEdges(i+N,j+N);
                        }
                    }
                }
            }

            for(int i = 0; i < N; ++i)
                if( !dfn[i])
                    TarBFS(i);
            int flag = 1;
            for(int i = 0; i < N; ++i)
                if(belong[i] == belong[i+N])
                    flag = 0;
            if(flag == 1)
                ans = mid,Left = mid + 1;
            else
                Right = mid - 1;
        }
        printf("%d\n",ans);
    }

    return 0;
}
时间: 2024-10-26 12:54:54

POJ2296 Map Labeler【2-SAT】【二分】的相关文章

Map Labeler (poj 2296 二分+2-SAT)

Language: Default Map Labeler Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 1815   Accepted: 599 Description Map generation is a difficult task in cartography. A vital part of such task is automatic labeling of the cities in a map; whe

POJ2296.Map Labeler——2-sat二分最大值+可行性判断

http://poj.org/problem?id=2296 题目描述: 在二维坐标在有n个点,在这n个点上放正方形,每个点只能放在正方形上/下边界的中点,要使得这n个点放置的正方形互不相交,求正方形的最大边长 分析: 每个正方形要么放上面,要么放下面,2种限制... 对第i个点,2*i表示放上面,2*i+1表示放下面.设边长为r 1.当abs(x[i]-x[j])>=r,则这两个正方形可以任意放 2.当abs(y[i]-y[j]) < r 2.1当y[i]==y[j]时,i和j的放法相反 i

poj 2296 Map Labeler【二分+2-set】【经典】

题目:poj 2296 Map Labeler 题意:给出以下二维坐标点,然后让你往平面上放正方形,点必须落在正方形上面边的中点或者下面边的中点,正方形不能重叠,可以共用边.问最大正方形边的边长. 分析:这种最大化最小值或者最小化最大值的问题,我们都可以种二分+判断的方法来解,这个也不例外,关键是判断部分 我们现在二分枚举边长为diff,然后所有的点就变成了在正方形上面或者下面的问题了,二选一的问题很明显可以用2-set来判断的 这个题目的关键在于理解他们之间的二元关系并建图,下面我们来分析 首

POJ 2296 Map Labeler(2-sat)

POJ 2296 Map Labeler 题目链接 题意: 坐标轴上有N个点,要在每个点上贴一个正方形,这个正方形的横竖边分别和x,y轴平行,并且要使得点要么在正方形的上面那条边的中点,或者在下面那条边的中点,并且任意两个点的正方形都不重叠(可以重边).问正方形最大边长可以多少? 思路:显然的2-sat问题,注意判断两个矩形相交的地方,细节 代码: #include <cstdio> #include <cstring> #include <cstdlib> #incl

POJ 2296 Map Labeler(二分边长+2-sat判解)(经典题)

题意:给你n个点,要你在这n个点上放一个正方形,点只能在正方形的上边或下边的中点上,所有正方形大小一样, 不能重叠,求最大的正方形. 经典的题目,找约束关系要经过一些讨论. //320 KB 16 ms #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int N = 222; int n; struct n

POJ 2296 Map Labeler

二分答案 + 2-SAT验证,判断正方形是否相交写起来有点烦,思路还是挺简单的. #include<cstdio> #include<cstring> #include<cmath> #include<stack> #include<queue> #include<algorithm> using namespace std; const int maxn=1005; struct Point { double x,y; }p[max

2-SAT问题

2-SAT问题 现有一个由N个布尔值组成的序列A,给出一些限制关系,比如A[x]AND A[y]=0.A[x] OR A[y] OR A[z]=1等,要确定A[0..N-1]的值,使得其满足所有限制关系.这个称为SAT问题,特别的,若每种限制关系中最多只对两个元素进行限制,则称为2-SAT问题. 由于在2-SAT问题中,最多只对两个元素进行限制,所以可能的限制关系共有11种: A[x] NOT A[x] A[x] AND A[y] A[x] AND NOT A[y] A[x] OR A[y] A

【图论】2-sat总结

2-sat总结 2-sat问题,一般表现的形式为.每一个点有两种方式a,b,要么选a,要么选b.而且点点之间有一些约束关系.比如:u和v至少一个选a.那么这就是一个表达式.把a当成真,b当成假,那就是u真或v真.2-sat的题目就是这样.给定这些约束,推断是否会矛盾 注意表达式的转化形式,(事实上就是离散数学中那几种转换方式) 比方(u真且v真)或(u假且v假)就能够转化成(u真或v假)且(u假或v真),这样就能建立关系 2-sat中的原理,事实上和2染色是一样的,把每一个结点拆分成一个真结点和

题单二:图论500

http://wenku.baidu.com/link?url=gETLFsWcgddEDRZ334EJOS7qCTab94qw5cor8Es0LINVaGMSgc9nIV-utRIDh--2UwRLvsvJ5tXFjbdpzbjygEdpGehim1i5BfzYgYWxJmu ==========  以下是最小生成树+并查集=========================[HDU]1213         How Many Tables        基础并查集★1272         小