Rectilinear Polygon UVA - 11106 贪心

问题

https://vjudge.net/problem/UVA-11106
给出n个坐标都是整数的顶点,连接成一个多边形,两点之间的边必须水平或者竖直的,每一个顶点都是一条水平边和一条竖直边的端点,输出这个多边形的周长。

分析

同一横坐标的点必须为偶数个,如果只有奇数个,那么会有一个点无法连接一条横向边,同理,同一纵坐标的点一定有偶数个。横坐标相同的两个相邻点一定连接,同理,纵坐标相邻的两个点一定相邻。
限制:所有的点必须连成一个环,边之间不能交叉。
用并查集检测所有的边是否相连(相连那么一定会联成一个环)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long LL;
const int maxn=100000+5;
int a,b,n,kase;
map<int,vector<pair<int,int>>> mx,my;
int fa[maxn];

inline int getFa(int x){
    if(x==fa[x]) return x;
    return fa[x]=getFa(fa[x]);
}

inline int cal(vector<pair<int,int>> &vi){
    int t=0,a,b;
    for(int i=1;i<vi.size();i+=2){
        t+=vi[i].first-vi[i-1].first;
        a=getFa(vi[i-1].second);
        b=getFa(vi[i].second);
        if(a!=b) fa[b]=a;
    }
    return t;
}

bool check(){
    int t=getFa(0);
    for(int i=1;i<n;++i){
        if(getFa(i)!=t) return false;
    }
    return true;
}

//判断是否相交
bool intersection(){
    for(auto &iter:my){
        vector<pair<int,int>> &vi=iter.second;
        int y=iter.first;
        for(int i=1;i<vi.size();i+=2){
            int x1=vi[i-1].first,x2=vi[i].first;
            auto iter2=mx.upper_bound(x1);
            while(iter2!=mx.end() && (iter2->first<x2)){
                vector<pair<int,int>> &vi2=iter2->second;
                for(int j=1;j<vi2.size();j+=2){
                    if(vi2[j-1].first<y && y<vi2[j].first)
                        return true;
                }
                ++iter2;
            }
        }
    }
    return false;
}

int main(void){
    scanf("%d",&kase);
    while(kase--){
        mx.clear();
        my.clear();
        scanf("%d",&n);
        for(int i=0;i<n;++i){
            scanf("%d%d",&a,&b);
            mx[a].push_back(make_pair(b,i));
            my[b].push_back(make_pair(a,i));
            fa[i]=i;
        }
        bool flag=false;
        int ans=0;
        for(auto &iter:mx){
            if(iter.second.size()%2){
                flag=true;
                break;
            }else{
                sort(iter.second.begin(),iter.second.end());
                ans+=cal(iter.second);
            }
        }
        if(flag){
            printf("-1\n");
            continue;
        }

        for(auto &iter:my){
            if(iter.second.size()%2){
                flag=true;
                break;
            }else{
                sort(iter.second.begin(),iter.second.end());
                ans+=cal(iter.second);
            }
        }
        if(flag){
            printf("-1\n");
            continue;
        }

        if(!check() || intersection()){
            printf("-1\n");
            continue;
        }
        printf("%d\n",ans);
    }
    return 0;
}

实际上,去掉测试边相交的函数 intersection()也能过去。

发布了180 篇原创文章 · 获赞 3 · 访问量 3445

猜你喜欢

转载自blog.csdn.net/zpf1998/article/details/105138439