PTA 一 水果忍者

2010年風靡全球的“水果忍者”遊戲,想必大家肯定都玩過吧?(沒玩過也沒關係啦~)在遊戲當中,畫面裏會隨機地彈射出一系列的水果與炸彈,玩家儘可能砍掉所有的水果而避免砍中炸彈,就可以完成遊戲規定的任務。如果玩家可以一刀砍下畫面當中一連串的水果,則會有額外的獎勵,如圖1所示。

圖 1

現在假如你是“水果忍者”遊戲的玩家,你要做的一件事情就是,將畫面當中的水果一刀砍下。這個問題看上去有些複雜,讓我們把問題簡化一些。我們將遊戲世界想象成一個二維的平面。遊戲當中的每個水果被簡化成一條一條的垂直於水平線的豎直線段。而一刀砍下我們也僅考慮成能否找到一條直線,使之可以穿過所有代表水果的線段。

圖 2

如圖2所示,其中綠色的垂直線段表示的就是一個一個的水果;灰色的虛線即表示穿過所有線段的某一條直線。可以從上圖當中看出,對於這樣一組線段的排列,我們是可以找到一刀切開所有水果的方案的。

另外,我們約定,如果某條直線恰好穿過了線段的端點也表示它砍中了這個線段所表示的水果。假如你是這樣一個功能的開發者,你要如何來找到一條穿過它們的直線呢?

輸入格式:

輸入在第一行給出一個正整數N\le 10^4104),表示水果的個數。隨後N行,每行給出三個整數xxy_1y1y_2y2,其間以空格分隔,表示一條端點爲(x, y_1)(x,y1)(x, y_2)(x,y2)的水果,其中y_1 > y_2y1>y2。注意:給出的水果輸入集合一定存在一條可以將其全部穿過的直線,不需考慮不存在的情況。座標爲區間 [-10^6, 10^6)[106,106) 內的整數。

輸出格式:

在一行中輸出穿過所有線段的直線上具有整數座標的任意兩點p_1(x_1, y_1)p1(x1,y1)p_2(x_2, y_2)p2(x2,y2),格式爲 x_1\quad y_1\quad x_2\quad y_2x1y1x2y2。注意:本題答案不唯一,由特殊裁判程序判定,但一定存在四個座標全是整數的解。

輸入樣例:

5
-30 -52 -84
38 22 -49
-99 -22 -99
48 59 -18
-36 -50 -72

輸出樣例:

-99 -99 -30 -52

算法思路:Graham's Scan法求凸包(這題要求上凸和下凸)。構成凸包的線必有一條以上滿足條件(這裏沒總結出來爲什麼,就畫了個圖感覺是這個樣子。。。)

#include<stdio.h>
#include<algorithm>
using namespace std;

int N;

struct Point
{
	int x, y;
}top[10000], down[10000];
int stop[10000], sdown[10000];

bool judgeT(Point a, Point b, Point c) {
	return 1ll*(b.y - a.y)*(c.x - b.x) > 1ll*(b.x - a.x)*(c.y - b.y);
}

bool judgeD(Point a, Point b, Point c) {
	return 1ll*(b.y - a.y)*(c.x - b.x) < 1ll*(b.x - a.x)*(c.y - b.y);
}

int compare(const void * a, const void* b) {
	Point *ap = (Point*)(a), *bp = (Point*)(b);
	if (ap->x < bp->x || (ap->x == bp->x&&ap->y < bp->y)) return -1;
	return 1;
}

int main() {
	scanf("%d", &N);
	int i;
	int x, y1, y2;
	for (i = 0; i<N; i++) {
		scanf("%d%d%d", &x, &y1, &y2);
		top[i].x = down[i].x = x;
		top[i].y = y1;
		down[i].y = y2;
	}
	qsort(top, N,sizeof(Point), compare);
	qsort(down, N, sizeof(Point), compare);
	int xp = 0, nt = N;
	for (i = 1; i < N; i++) {
		if (top[i].x == top[xp].x) {
			top[i].x = 100000000;
			top[xp].y = min(top[i].y, top[xp].y);
			nt--;
		}
		else xp = i;
	}
	xp = 0;
	for (i = 1; i < N; i++) {
		if (down[i].x == down[xp].x) {
			down[i].x = 100000000;
			down[xp].y = max(down[i].y, down[xp].y);
		}
		else xp = i;
	}
	qsort(top, N, sizeof(Point), compare);
	qsort(down, N, sizeof(Point), compare);
	N = nt;
	if (N == 1) {
		printf("%d %d %d %d\n", x, y1, x, y2);
		return 0;
	}
	int tpre = 0, dpre = 0;
	for (i = 0; i < N; i++) {
		while (tpre >= 2 && judgeT(top[stop[tpre - 2]], top[stop[tpre - 1]], top[i])) tpre--;
		stop[tpre++] = i;
		while (dpre >= 2 && judgeD(down[sdown[dpre - 2]], down[sdown[dpre - 1]], down[i])) dpre--;
		sdown[dpre++] = i;
	}
	int j;
	for (i = 0; i < tpre - 1; i++) {
		for (j = 0; j < dpre; j++)
			if (judgeT(top[stop[i]], down[sdown[j]], top[stop[i + 1]])) break;
		if (j == dpre)
			break;
	}
	Point left, right;
	if (i == tpre - 1) {
		for (i = 0; i < dpre - 1; i++) {
			for (j = 0; j < tpre; j++)
				if (judgeD(down[sdown[i]], top[stop[j]], down[sdown[i + 1]])) break;
			if (j == tpre)
				break;
		}
		left = down[sdown[i]];
		right = down[sdown[i + 1]];
	}
	else {
		left = top[stop[i]];
		right = top[stop[i + 1]];
	}
	printf("%d %d %d %d\n", left.x, left.y, right.x, right.y);
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章