2016 ICPC Mid-Central USA Region J. Windy Path (贪心)
比赛链接:2016 ICPC Mid-Central USA Region
题目链接:Windy Path
Description

Consider following along the path in the figure above, starting from \((4,4)\) and moving to \((2,5)\). Then the path turns rightward toward \((1,6)\), then sharp left to \((5,0)\) and finally sharp left again to \((4,2)\). If we use ‘\(L\)’ for left and ‘RR’ for right, we see that the sequence of turn directions is given by RLL. Notice that the path does not cross itself: the only intersections of segments are the connection points along the path.
Consider the reverse problem: Given points in an arbitrary order,say \((2,5),(1,6),(4,4),(5,0),(4,2)\),could you find an ordering of the points so the turn directions along the path are given by RLL? Of course to follow the path in the figure,you would start with the third point in the list \((4,4)\),then the first \((2,5)\),second \((1,6)\), fourth \((5,0)\), and fifth \((4,2)\), so the permutation of the points relative to the given initial order would be: \(3\ 1 \ 2 \ 4 \ 5\).
Input
The first line of the input contains an integer \(N\), specifying the number of points such that \(3 \le N \le 50\). The following NN lines each describe a point using two integers \(x_i\) and \(y_i\) such that \(0 \le x_i,y_i \le 1000\). The points are distinct and no three are collinear (i.e., on the same line). The last line contains a string of \(N - 2\) characters, each of which is either ‘\(L\)’ or ‘\(R\)’.
Output
A permutation of\(\{ 1,...,N \}\) that corresponds to a nonintersecting path satisfying the turn conditions. The numbers are to be displayed with separating spaces. (There are always one or more possible solutions, and any one may be used.)
Solution
题意
给定 \(n\) 个点的坐标和一个包含 \(R\) 和 \(L\) 的序列,其中 \(L\) 代表左转,\(R\) 代表右转,求一个访问每个点顺序满足给定的序列。
题解
贪心 构造 计算几何
由于是 special judge,只要想出一种构造方法就可以。本题可以贪心。
- 首先选择最下面最左边的点作为起点,(起点不唯一,比如最左边最下面也可以)。
- 如果第一个字符是 \(R\),第二个点选择最左边的点;反之选择最右边的点。
- 之后每次考察连续两个字符:
- 如果是 \(RL\),选择右边最后一个
- 如果是 \(LR\),选择左边最后一个
- 如果是 \(RR\),选择右边第一个
- 如果是 \(RR\),选择左边第一个
判断点是在向量的左边还是右边可以用 \(ToLeftTest\),查询第一个还是最后一个可以用夹角判断。
/*
思路:
贪心
1. R: 左边第一个
2. L: 右边第一个
3. RL: 右边最后一个
4. LR: 左边最后一个
5. LL: 左边第一个
6. RR: 右边第一个
*/
#include <bits/stdc++.h>
using namespace std;
struct Point {
int x, y, index;
} p[100];
int area2(Point p, Point q, Point s) {
return p.x * q.y - p.y * q.x + q.x * s.y - q.y * s.x + s.x * p.y - s.y * p.x;
}
// 判断某个点在向量的左边还是右边
bool toLeftTest(Point p, Point q, Point s) {
return area2(p, q, s) > 0;
}
int cmp(Point p1, Point p2) {
if (p1.y == p2.y)
return p1.x < p2.x;
return p1.y < p2.y;
}
// 求向量 pq 与 向量 ps 之间的夹角
double ang(Point p, Point q, Point s) {
double x1 = q.x - p.x, y1 = q.y - p.y;
double x2 = s.x - p.x, y2 = s.y - p.y;
double ans = (x1 * x2 + y1 * y2) / (sqrt(x1 * x1 + y1 * y1) * sqrt(x2 * x2 + y2 * y2));
return acos(ans);
}
vector<Point> ans; // 存放答案
int vis[100]; // 标记已访问过的点
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d%d", &p[i].x, &p[i].y);
p[i].index = i;
}
sort(p + 1, p + n + 1, cmp);
ans.push_back(p[1]); // 起点
vis[p[1].index] = 1;
double min_ang = 10;
int min_index = 1;
Point tmp, tmp2 = p[1]; // 保存上两个点
string str;
cin >> str;
// 第一个点
if (str[0] == 'R') {
tmp.x = p[1].x - 1;
tmp.y = p[1].y;
for (int i = 2; i <= n; ++i) {
double angle = ang(p[1], p[i], tmp);
if (angle < min_ang) {
min_ang = angle;
min_index = i;
}
}
ans.push_back(p[min_index]);
vis[p[min_index].index] = 1;
} else {
tmp.x = p[1].x + 1;
tmp.y = p[1].y;
for (int i = 2; i <= n; ++i) {
double angle = ang(p[1], p[i], tmp);
if (angle < min_ang) {
min_ang = angle;
min_index = i;
}
}
ans.push_back(p[min_index]);
vis[p[min_index].index] = 1;
}
tmp = p[min_index];
// 之后的点
for (int i = 0; i < str.size() - 1; ++i) {
if (str[i] == 'R' && str[i + 1] == 'L') {
min_ang = 10;
for (int i = 1; i <= n; ++i) {
if (vis[p[i].index])
continue;
if (toLeftTest(tmp2, tmp, p[i]))
continue;
double angle = ang(tmp, tmp2, p[i]);
if (min_ang > angle) {
min_ang = angle;
min_index = i;
}
}
ans.push_back(p[min_index]);
vis[p[min_index].index] = 1;
tmp2 = tmp;
tmp = p[min_index];
}
else if (str[i] == 'R' && str[i + 1] == 'R') {
min_ang = 0;
for (int i = 1; i <= n; ++i) {
if (vis[p[i].index])
continue;
if (toLeftTest(tmp2, tmp, p[i]))
continue;
double angle = ang(tmp, tmp2, p[i]);
if (min_ang < angle) {
min_ang = angle;
min_index = i;
}
}
ans.push_back(p[min_index]);
vis[p[min_index].index] = 1;
tmp2 = tmp;
tmp = p[min_index];
} else if (str[i] == 'L' && str[i + 1] == 'R') {
min_ang = 10;
for (int i = 1; i <= n; ++i) {
if (vis[p[i].index])
continue;
if (!toLeftTest(tmp2, tmp, p[i]))
continue;
double angle = ang(tmp, tmp2, p[i]);
if (min_ang > angle)
{
min_ang = angle;
min_index = i;
}
}
ans.push_back(p[min_index]);
vis[p[min_index].index] = 1;
tmp2 = tmp;
tmp = p[min_index];
} else {
min_ang = 0;
for (int i = 1; i <= n; ++i) {
if (vis[p[i].index])
continue;
if (!toLeftTest(tmp2, tmp, p[i]))
continue;
double angle = ang(tmp, tmp2, p[i]);
if (min_ang < angle) {
min_ang = angle;
min_index = i;
}
}
ans.push_back(p[min_index]);
vis[p[min_index].index] = 1;
tmp2 = tmp;
tmp = p[min_index];
}
}
// 最后一个点
for (int i = 1; i <= n; ++i) {
if (!vis[p[i].index]) {
ans.push_back(p[i]);
break;
}
}
for (int i = 0; i < ans.size(); ++i) {
printf("%d", ans[i].index);
printf("%s", i == ans.size() - 1 ? "\n" : " ");
}
return 0;
}
2016 ICPC Mid-Central USA Region J. Windy Path (贪心)的更多相关文章
- 2016 ICPC总结
2016 ICPC总结 九月份开学,开始知识点的补充,刚开始的几周都在刷acmsteps,十月开始进行专题性的学习,首先进行的数据结构,给自己定的计划,十一月前看完数据结构,刚开始的时候看的都是以前的 ...
- HYNB Round 8: 2016 ICPC Amritapuri Regionals
HYNB Round 8: 2016 ICPC Amritapuri Regionals A - Tim and BSTs 做法 经典的树 DP 问题. \(dp[u][i]\) 表示考虑以 u 为根 ...
- ICPC North Central NA Contest 2018
目录 ICPC North Central NA Contest 2018 1. 题目分析 2. 题解 A.Pokegene B.Maximum Subarrays C.Rational Ratio ...
- ICPC Mid-Central USA Region 2019 题解
队友牛逼!带我超神!蒟蒻的我还是一点一点的整理题吧... Dragon Ball I 这个题算是比较裸的题目吧....学过图论的大概都知道应该怎么做.题目要求找到七个龙珠的最小距离.很明显就是7个龙珠 ...
- 2016 ICPC青岛站---k题 Finding Hotels(K-D树)
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5992 Problem Description There are N hotels all over ...
- HDU 5884 Sort -2016 ICPC 青岛赛区网络赛
题目链接 #include <iostream> #include <math.h> #include <stdio.h> #include<algorith ...
- 2013 ACM/ICPC Asia Regional Changsha Online J Candies
AC了,但是不知道为什么,但是恶心的不得了~最近写代码,思路都非常清晰,但是代码各种bug~T.T~说说思路吧:二分~330ms~ 小队友fribbi的思路是离线250msAC~ 预处理solve函数 ...
- ICPC 2018 南京网络赛 J Magical Girl Haze(多层图最短路)
传送门:https://nanti.jisuanke.com/t/A1958 题意:n个点m条边的路,你有k次机会将某条路上的边权变为0,问你最短路径长度 题解:最短路变形,我们需要在常规的最短路上多 ...
- 2016 ICPC大连站---F题 Detachment
题意:输入一个x,将x拆分成一些小的数(这些数不能相同,即x=a1+a2+...... ai!=aj when i!=j),然后这些数相乘得到一个成积(s=a1*a2*......),求最大的乘积 ...
随机推荐
- MySQL-存储过程动态执行sql
存储过程动态执行 sql --存储过程名和参数,参数中in表示传入参数,out标示传出参数,inout表示传入传出参数 create procedure p_procedurecode(in sumd ...
- 92、R语言分析案例
1.读取数据 > bank=read.table("bank-full.csv",header=TRUE,sep=";") > 2.查看数据结构 & ...
- 项目集成swagger,并暴露指定端点给swagger
项目集成swagger 一:思考: 1.swagger解决了我们什么问题? 传统开发中,我们在开发完成一个接口后,为了测试我们的接口,我们通常会编写单元测试,以测试我们的接口的可用性,或者用postm ...
- Java输入/输出教程
Java输入/输出(I/O)处理从源读取数据并将数据写入目标.通常,读取存储在文件中的数据或使用I/O将数据写入到文件中. java.io和java.nio包中包含处理输入/输出的Java类.java ...
- python *arg和**kwargs的区别
转载自:https://www.cnblogs.com/yunguoxiaoqiao/p/7626992.html 一.*args的使用方法 *args 用来将参数打包成tuple给函数体调用 举个栗 ...
- 基于MFC的Media Player播放器的制作(1---播放器界面的布局)
| 版权声明:本文为博主原创文章,未经博主允许不得转载. 通过上面的一些预备知识,我们现在就可以自己来制作基于MFC的播放器了,接下来我们讲的是使用MFC制作我们播放器 的界面. 首先,我们我们打 ...
- tire 树入门
博客: 模板: 前缀是否出现: /* trie tree的储存方式:将字母储存在边上,边的节点连接与它相连的字母 trie[rt][x]=tot:rt是上个节点编号,x是字母,tot是下个节点编号 * ...
- Ubuntu 14.04 Sublime Text3 Java编译运行(最简单的方法)
Sublime,结果发现只能编译,无法直接运行,于是就在网上搜解决方法,发现大部分方法都是告诉你要进入Java.sublime-packag这个文件,然后再修改JavaC.sublime-build, ...
- 编译Android源代码
硬盘空间需要在50G以上,最好100g 系统:ubuntu14.04 交叉工具链:arm-linux-gcc-4.5.1-v6-vfp-20120301 安装 Java 开发环境 $ sudo apt ...
- teb教程1
http://wiki.ros.org/teb_local_planner/Tutorials/Setup%20and%20test%20Optimization 简介:本部分关于teb怎样优化轨迹以 ...