JZOJ 3.10 1539——三条直线

题目描述

FJ想使用购买的新监控系统监视他的N头奶牛(1 <=N<= 50,000)。

第i头牛位置在(x_i, y_i),这是一对整数坐标,范围在0…1,000,000,000之内。FJ的监控系统有3个特殊的镜头,每一个镜头能够观察垂直或者水平的一行。

请决定FJ是否有可能架设这3个镜头,使他能够观察到所有的N头牛。也就是说,请决定N头牛的位置是否能同时被3条直线所覆盖。这3条直线必须是垂直或者水平的。

输入

第1行:1个整数N

第2..N+1行:2个整数x_i和y_i,表示第i头牛的坐标

输出

第1行:如果能监控所有的N头牛,则输出1,否则输出0

样例输入

6

1 7

0 0

1 2

2 0

1 4

3 4

样例输出

1


思路

这题DFS爆搜。
首先,用c[i]来记录i这行或这列的奶牛数,用d来记录还有多少行或列没有被覆盖。
如果一次循环过去d<=3就直接退出;
否则,去枚举覆盖这个点,能不能将所有点覆盖,也就是d<=2。能就退出,不能就回溯。
如果一次dfs枚举不出来,我们就将横竖坐标交换,再做一次dfs

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
const int maxn=1001000;
pair<int,int> l[maxn];
map<int, int> c;
int d;
int n;
void inc(int x) 
{
    if(c[x]==0) d++;
    c[x]=c[x] + 1;
}

void dec(int x) 
{
    c[x]=c[x]-1;
    if(c[x]==0) d--;
}

int dfs() {
    sort(l,l+n);
    d= 0;
    c.clear();
    for(int i=0;i<n;++i) 
    {
        inc(l[i].second);
    }
    if(d<=3) return 1;
    int i=0,j=0;
    while(i<n) 
    {
        while(j<n && l[i].first==l[j].first) j++;
        for(int i2 =i; i2<j;++i2) dec(l[i2].second);
        if(d<=2) return 1;
        for(int i2 =i; i2<j;++i2) inc(l[i2].second);
        i=j;
    }
    return 0;
}
int main() 
{
    freopen("3lines.in","r",stdin);
    freopen("3lines.out","w",stdout);
    scanf("%d",&n);
    for(int i=0;i<n;++i) 
        scanf("%d%d",&l[i].first,&l[i].second);
    if(dfs()) 
    {
        printf("1");
    }
    else 
    {
        for(int i=0;i<n;++i) 
        {
            swap(l[i].first,l[i].second);
        }
        if(dfs()) printf("1");
        else printf("0");
    }
    return 0;
}
posted @ 2017-03-11 16:32  BEYang_Z  阅读(242)  评论(0编辑  收藏  举报