USACO2011Open Bronze 3lines 題解

[思路]
符合 FJ的要求有兩種情況:三條直線平行或者兩條直線平行並與一條直線垂直.至於橫豎的問題,可以通過反轉奶牛的座標轉化成相同的方式.

三條平行直線:

把所有點的橫座標記錄下來,如果不同的橫座標個數小於等於3,那麼符合條件.

兩條平行與一條直線垂直:
把所有的縱座標和它們個數記下,也記下所有出現的縱座標個數,再按照橫座標排序,再枚舉一個橫座標a,表示這條直線x=a與其他兩條橫線垂直,再把這條直線上的所有縱座標cnt--,再看縱座標出現的個數,如果<=2,說明成立.

標程寫的比我的精煉很多,那我就放標程吧…

#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
const int MAXN = 1001000;
pair<int,int> lis[MAXN];
map<int, int> cou;
int distinct;
int n;
void inc(int x) {
	if(cou[x] == 0) {
		distinct++;//不同縱座標的個數
	}
	cou[x] = cou[x] + 1;
}

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

int moo() {
	sort(lis, lis + n);//排序,把相同橫座標的放在一起
	distinct = 0;
	cou.clear();
	for(int i = 0; i < n; ++i) {
		inc(lis[i].second);
	}
	if(distinct <= 3) return 1;//三條平行
	int i = 0, i1 = 0;
	while(i < n) {
		while(i1 < n && lis[i].first == lis[i1].first) i1++;
		for(int i2 = i; i2 < i1; ++i2) dec(lis[i2].second);//刪除一條豎線上的所有縱座標
		if(distinct <= 2)  return 1;
		for(int i2 = i; i2 < i1; ++i2) inc(lis[i2].second);
		i = i1;
	}
	return 0;
}
int main() {
	scanf("%d", &n);
	for(int i = 0; i < n; ++i) 
scanf("%d%d", &lis[i].first, &lis[i].second);
	if(moo()) {
		puts("1");
	}
	else {
		for(int i = 0; i < n; ++i) {
			swap(lis[i].first, lis[i].second);//把座標反轉
		}
		if(moo()) puts("1");
		else puts("0");
	}
	return 0;
}


發佈了39 篇原創文章 · 獲贊 2 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章