ZOJ 3764 Easy billiards 月赛E题

Edward think a game of billiards is too long and boring. So he invented a new game called Easy billiards.

Easy billiards has N balls on a brimless rectangular table in the beginning, and your goal is try to make the number of balls on the table as least as possible by several hit under the following rules:

1: The direction you hit the balls should parallel to the tables border.

2: If ball A crashed into ball B, ball B will moves in the same direction of ball A before the crashing, and ball A will stop in the place of ball B before the crashing.

3: If ball C is moving and there are no balls in front of ball C, it will runs out of the tables border, that means ball C is out of the table.

4: You can choose arbitrary ball on the table to hit, but on a hit, you can't let the ball you choose to hit runs out of the tables border. In another word, a ball could runs out of the table if and only if it was crashed by another ball in a hitting.

Now, Edward wants to know the least number of balls remained on the table after several hits, and how.

Input

There are multiple test cases. For each test cases, in the first line, there is an integer N, which means the number of the balls on the table. There are following N lines, each line contains two integers Xi and Yi, which means the coordinate of ball I. (0<=N<=2000, 0<=XiYi<=10^8)

Output

For each test cases, you should output the least number of balls on the first line. And you should output several lines to show the order of hits following the first line, each line should contains the coordinate of the ball you choose to hit and the direction you hit. (LEFT,RIGHT,UP,DOWN).

Sample Input
4
0 0
2 0
4 0
2 2
9
1 1
2 1
3 1
1 2
2 2
3 2
1 3
2 3
3 3
Sample output
1
(2, 2) DOWN
(4, 0) LEFT
(2, 0) LEFT
1
(1, 3) DOWN
(1, 2) DOWN
(2, 3) DOWN
(2, 2) DOWN
(3, 3) DOWN
(3, 2) DOWN
(3, 1) LEFT
(2, 1) LEFT
题意:桌面上一些球,能从4个方向打球,球撞到球会把球往那个方向撞,自己停下,如果撞不到球了就会飞出边界,问一个撞击顺序使得最后桌面上的球最少。
思路:球和周围能撞的球为边建图,每部分的图最后肯定剩下一个球,然后去DFS找出路径。
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 2005;
#define INF 0x3f3f3f3f
int n, ansn, vis[N];
struct Point {
	int x, y, id;
	Point() {}
	Point(int xx, int yy, int iid) {
		x = xx; y = yy; id = iid;
	}
} p[N], ans[N];
vector<int> g[N];
bool cmpx(Point a, Point b) {
	if (a.x != b.x)
		return a.x < b.x;
	return a.y < b.y;
}

bool cmpy(Point a, Point b) {
	if (a.y != b.y)
		return a.y < b.y;
	return a.x < b.x;
}

bool cmpid(Point a, Point b) {
	return a.id < b.id;
}
void build() {
	int i;
	sort(p + 1, p + 1 + n, cmpx);
	for (i = 2; i <= n; i++) {
		if (p[i].x == p[i - 1].x) {
			g[p[i].id].push_back(p[i - 1].id);
			g[p[i - 1].id].push_back(p[i].id);
		}
	}
	sort(p + 1, p + 1 + n, cmpy);
	for (i = 2; i <= n; i++) {
		if (p[i].y == p[i - 1].y) {
			g[p[i].id].push_back(p[i - 1].id);
			g[p[i - 1].id].push_back(p[i].id);
		}
	}
	sort(p + 1, p + 1 + n, cmpid);
}
//0L 1R 2U 3D
const char D[4][20] = {"LEFT", "RIGHT", "UP", "DOWN"};
void dfs(int v) {
	int i;
	vis[v] = 1;
	for (i = 0; i < g[v].size(); i++) {
		int u = g[v][i];
		if (vis[u]) continue;
		dfs(u);
		if (p[u].x == p[v].x) {
			if (p[u].y < p[v].y) {
				Point an(p[u].x, p[u].y, 2);
				ans[ansn++] = an;
			}
			else {
				Point an(p[u].x, p[u].y, 3);
				ans[ansn++] = an;
			}
		}
		else if (p[u].y == p[v].y) {
			if (p[u].x < p[v].x) {
				Point an(p[u].x, p[u].y, 1);
				ans[ansn++] = an;
			}
			else {
				Point an(p[u].x, p[u].y, 0);
				ans[ansn++] = an;
			}
		}
	}
}

void solve() {
	for (int i = 1; i <= n; i++) {
		if (vis[i]) continue;
		dfs(i);
	}
	printf("%d\n", n - ansn);
	for (int j = 0; j < ansn; j++)
		printf("(%d, %d) %s\n", ans[j].x, ans[j].y, D[ans[j].id]);
}

int main() {
	while (scanf("%d", &n) == 1) {
		ansn = 0;
		memset(vis, 0, sizeof(vis));
		for (int i = 1; i <= n; i++) {
			scanf("%d%d", &p[i].x, &p[i].y);
			g[i].clear();
			p[i].id = i;
		}
		build();
		solve();
	}
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值