POJ 2296 Map Labeler(2-SAT)

POJ 2296 Map Labeler(2-SAT)

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

题意:

        平面上有n个给定坐标且不重叠的点,现在每个点要画一个大小相同的正方形(各边平行于坐标轴),对于每个点来说,该点只能在该正方形的上边的中点或下边的中点.现在的问题是,该正方形最大边长能为多少(整数),且各个点的正方形还能不重叠?

分析:

        其实每个点只有两种选择,朝上画或者朝下画.对于任意两个点a和b来说,假设a=0表示朝上画,a=1表示朝下画.那么如果对于固定正方形长度mid来说, a朝上且b朝上时,正方形如果重叠,那么可以推出边: a = 0 -> b=1 且b=0 -> a=1. 依次类推.

        假设点都存在结构体s[n]中,如果abs(s[i].x-s[j].x)>= mid ,则可以随便放.(i取0表示上放,i取1表示下放)

        否则abs(s[i].x-s[j].x)<mid时:

        1.abs(s[i].y-s[j].y)==0,则必须一个放上,一个放下. add(i,0,j,1) add(i,1,j,0), add(j,0,i,1), add(j,1,i,0)

        2.0<abs(s[i].y-s[j].y)<mid, 则必须上面的点上放,下面的点下放. 假设i点在上,j点在下(即 s[i].y > s[j].y) ,则add(i,1,i,0) 且add(j,0,j,1)

        3.mid<=abs(s[i].y-s[j].y)<2*mid,则只有一种情况不合法,即上面的点往下放且下面的点往上放. 假设i点在上,则:

add(i,1,j,1) 且 add(j,0,i,0)

AC代码:

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn= 100+10;
int n;  //点个数
struct TwoSAT
{
    int n;
    vector<int> G[maxn*2];
    int S[maxn*2],c;
    bool mark[maxn*2];

    bool dfs(int x)
    {
        if(mark[x^1]) return false;
        if(mark[x]) return true;
        mark[x]=true;
        S[c++]=x;
        for(int i=0;i<G[x].size();i++)
            if(!dfs(G[x][i])) return false;
        return true;
    }

    void init(int n)
    {
        this->n=n;
        for(int i=0;i<n*2;i++) G[i].clear();
        memset(mark,0,sizeof(mark));
    }

    void add_clause(int x,int xval,int y,int yval)
    {
        x=x*2+xval;
        y=y*2+yval;
        G[x].push_back(y);
    }

    bool solve()
    {
        for(int i=0;i<2*n;i+=2)
        if(!mark[i] && !mark[i+1])
        {
            c=0;
            if(!dfs(i))
            {
                while(c>0) mark[S[--c]]=false;
                if(!dfs(i+1)) return false;
            }
        }
        return true;
    }
}TS;
struct Node
{
    int x,y;
}s[maxn];
bool ok(int mid)
{
    TS.init(n);
    for(int i=0;i<n;i++)
    for(int j=i+1;j<n;j++)
    if(abs(s[i].x-s[j].x) < mid)
    {
        if(s[i].y==s[j].y)
        {
            TS.add_clause(i,0,j,1);
            TS.add_clause(i,1,j,0);
            TS.add_clause(j,0,i,1);
            TS.add_clause(j,1,i,0);
        }
        else if( abs(s[i].y-s[j].y) < mid )
        {
            if(s[i].y > s[j].y)
            {
                TS.add_clause(i,1,i,0);
                TS.add_clause(j,0,j,1);
            }
            else
            {
                TS.add_clause(i,0,i,1);
                TS.add_clause(j,1,j,0);
            }
        }
        else if( abs(s[i].y-s[j].y) < 2*mid )
        {
            if(s[i].y > s[j].y)
            {
                TS.add_clause(i,1,j,1);
                TS.add_clause(j,0,i,0);
            }
            else
            {
                TS.add_clause(j,1,i,1);
                TS.add_clause(i,0,j,0);
            }
        }
    }
    return TS.solve();
}
int main()
{
    int T; scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&s[i].x,&s[i].y);
        }

        int L=0,R=20000+1;
        while(R>L)
        {
            int mid = L+(R-L+1)/2;
            if(ok(mid)) L=mid;
            else R=mid-1;
        }
        printf("%d\n",L);
    }
    return 0;
}


你可能感兴趣的:(Algorithm,算法,ACM)