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

题目:poj 2296 Map Labeler

题意:给出以下二维坐标点,然后让你往平面上放正方形,点必须落在正方形上面边的中点或者下面边的中点,正方形不能重叠,可以共用边。问最大正方形边的边长。

分析:这种最大化最小值或者最小化最大值的问题,我们都可以种二分+判断的方法来解,这个也不例外,关键是判断部分

我们现在二分枚举边长为diff,然后所有的点就变成了在正方形上面或者下面的问题了,二选一的问题很明显可以用2-set来判断的

这个题目的关键在于理解他们之间的二元关系并建图,下面我们来分析

首先,对于一个点a,在正方形的上边上,设为点a,在下边上设为点-a。

b同样的,上边上设为点b,下边上设为-b

对于任意两个点a和b

如果a和b的横坐标只差小于diff

如果纵坐标值相等,那么只能是一个在上面一个在下面,表示而二元关系为(a | b)即a和b只能有一个在上边上,改写成等价形式

(a&-b)|(-a&b)即a在上边则b必然在下边,a在下边的话b必然在上边,我们在加边的时候要求强连通分量,所以这里可以按无向边建图。

如果纵坐标的值小于diff,则纵坐标值大的所在正方形必然位于上面,小的位于下面,我们假设a的纵坐标大于b,我们可以让a–>-a,-b–>b,为什么呢?因为我们必然要让a的四边形位于上面,即点在下边上,这样连边如果点在上边,则会形成a个-a属于同一个强连通分量导致可行,so..

如果纵坐标的值小于2*diff,同样假设a纵坐标的大于b,那么a的四边形在下,则b的必然在下,b的在上则a的必然也在上所以-a–>-b,b–>a

这用只要同s-set跑是否可行就ok

对其中的一些关系的建图还是很经典的。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <stack>
using namespace std;
const int N = 2200;

struct TwoSet
{
    int dfs_clock,tpnum;
    stack<int> sta;
    vector<int> G[2*N];
    bool vis[2*N];
    int dfn[2*N],low[2*N],tp[2*N];
    void init(int n)
    {
        for(int i=0; i<=2*n; i++)
            G[i].clear();
        dfs_clock = tpnum = 0;
        memset(vis,false,sizeof(vis));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(tp,0,sizeof(tp));
        while(!sta.empty())
            sta.pop();

    }
    void add(int x,int y)
    {
        G[x].push_back(y);
    }
    void add_Node(int x,int y)
    {
        add(x,y+1);
        add(x+1,y);
        add(y+1,x);
        add(y,x+1);
    }
    void Tarjan(int x)
    {
        sta.push(x);
        vis[x] = true;
        dfn[x] = low[x] = ++dfs_clock;
        for(int i=0; i<G[x].size(); i++)
        {
            int y = G[x][i];
            if(!dfn[y])
            {
                Tarjan(y);
                low[x] = min(low[x],low[y]);
            }
            else
            {
                if(vis[y])
                    low[x] = min(low[x],dfn[y]);
            }
        }
        if(low[x] == dfn[x])
        {
            tpnum++;
            do
            {
                x = sta.top();
                sta.pop();
                vis[x] = false;
                tp[x] = tpnum;
            }
            while(low[x] != dfn[x]);
        }
    }
    bool yougth(int n)
    {
        for(int i=0; i<2*n; i++)
            if(!dfn[i])
                Tarjan(i);
        for(int i=0; i<n; i++)
            if(tp[i]==tp[i+n])
                return false;
        return true;
    }
};
TwoSet solver;
struct Node
{
    int x,y;
};
Node re[N];

bool test(int diff,int n)
{
    solver.init(n);
    for(int i=0; i<n; i++)
    {
        for(int j=i+1; j<n; j++)
        {
            if(abs(re[i].x-re[j].x)<diff)
            {
                if(re[i].y==re[j].y)
                    solver.add(i,j+n),solver.add(j,i+n),solver.add(j+n,i),solver.add(i+n,j);
                else if(re[i].y>re[j].y&&(re[i].y-re[j].y<diff))
                    solver.add(i,i+n),solver.add(j+n,j);
                else if(re[j].y>re[i].y&&(re[j].y-re[i].y<diff))
                    solver.add(j,j+n),solver.add(i+n,i);
                else if(re[i].y>re[j].y&&(re[i].y-re[j].y)<2*diff)
                    solver.add(i,j),solver.add(j+n,i+n);
                else if(re[j].y>re[i].y&&(re[j].y-re[i].y)<2*diff)
                    solver.add(j,i),solver.add(i+n,j+n);
            }
        }
    }
    return solver.yougth(n);
}

int main()
{
//    freopen("Input.txt","r",stdin);
    int cas,n;
    scanf("%d",&cas);
    while(cas--)
    {
        scanf("%d",&n);
        for(int i=0; i<n; i++)
            scanf("%d%d",&re[i].x,&re[i].y);
        int l = 0,r = 0x3f3f3f3f,mid;
        int ans = -1;
        while(l<=r)
        {
            solver.init(n);
            mid = (l+r)>>1;
            if(test(mid,n))
                ans = mid,l = mid+1;
            else r = mid-1;
        }
        printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-08-05 09:21:35

poj 2296 Map Labeler【二分+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

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

POJ 2263 Heavy Cargo(二分+并查集)

题目地址:POJ 2263 这题是在网上的一篇关于优先队列的博文中看到的..但是实在没看出跟优先队列有什么关系..我用的二分+并查集做出来了... 二分路的载重量.然后用并查集检查是否连通. 代码如下: #include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <ctype.h> #

poj 3977 Subset 枚举+二分

首先分成一半2^17和2^18,并且把其中一半变成相反数,然后枚举一半二分查找另一半,在找到的位置前后也找找. 这里用到了二级排序,有很多细节要处理,不多说了. 巨坑的一个地方就是,不能用系统的abs,要自己手写,简直坑死.. #include<cstdio> #include<algorithm> #include<iostream> #include<map> using namespace std; typedef long long ll; stru

POJ 2112 Optimal Milking 二分答案+最大流

首先二分最长的边,然后删去所有比当前枚举的值长的边,算最大流,看是否能满足所有的牛都能找到挤奶的地方 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include

POJ 3228Gold Transportation(二分+最大流)

题目地址:POJ3288 这个题跟之前的一道题混了,感觉是一样的,所以连想都没怎么想就拆点然后求最短路然后二分求最大流了.结果连样例都不过,还一直以为又是哪里手残了..结果看了看样例,手算也确实不对,,.后来就没拆点,直接在原点上建的图,结果样例就过了..然后提交1次AC... 后来仔细的想了想,这题是问每一段路的最短的,而不是整个的最短的.所以说不应该拆点.而我混的那道题(poj2391)是问的走完的总的最小值. 这题的建图就是建一源点与汇点,将每个金矿与源点相连,权值为金矿数,与汇点也相连,

POJ 2391Ombrophobic Bovines(二分+最短路+网络流之最大流)

题目地址:http://poj.org/problem?id=2391 这个题WA了一晚上,原因是数组开小了,然后又TLE了一天,原因是数组改的过大了....不多说什么了... 思路不难,建图也不难,二分时间,然后把每个田地之间的最短距离用floyd最短路求出来.然后建立一个源点与汇点,将田地拆分成两个点,在距离之内的进行连边,要单向连边.然后将源点与田地相连,权值为每个田地的牛的数目,再把另一边的田地与汇点相连,权值为每个田地最大可避雨的牛的数目.拆开的田地之间权值可以为无穷大. 代码如下: