题目描述
平面上有 n个无限长的不垂直或平行于地面的扶手电梯,可以看做一些一次函数,并且这些电梯方向均朝右即 x 轴正方向
两个电梯的交点可以花费1代价换乘
此时人物在第(x_1)个电梯的横坐标为$ y_1$ 位置。
( exttt{piggy})在第 (x_2)个电梯的横坐标为 (y_2) 位置。
请问他最少花多少 代价才能过去?
输入格式
第一行一个正整数 n。
第二行四个整数 x_1,y_1,x_2,y_2 。
接下来 n 行,第 i 行两个数 k_i,b_i ,表示电梯的解析式为 y=k_ix+b_i
输出格式
最少花多少 代价如果无法到达,输出 -1。
输入输出样例
输入 #1
1
1 1 1 2
50 -30
输出 #1
0
输入 #2
2
1 2 2 2
1 0
2 0
输出 #2
-1
输入 #3
2
1 -1 2 1
1 0
2 0
输出 #3
1
说明/提示
本题采用 Subtask。
(Subtask1(20pts):1 le n le 10)
(Subtask2(30pts):1 le nle 1000)
(Subtask3(50pts):1 le x_1,x_2 le nle 10^5\-10^3 le y_1,y_2,k_i,b_i le 10^3)
题目分析
首先是结论:如果能到目标点,那么最多转换2次即可到达
然后是特殊情况,如下:
令起终点为(x1,y1),(x2,y2)
- 起点终点在同一直线,代价为0
- 起点所在直线(l_1)与终点所在直线(l_2)交点位于x1,x2之间,可以直接换乘1次
- 起终点直线交点不满足条件,通过第三方直线换乘2次。枚举换乘直线,判断交点顺序是否从左到右
本题需要通过平面几何,考虑特殊情况
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
struct Line
{
int k, b;
} lines[100005];
int n;
int sx, sy, ex, ey;
double getCrossX(int l1, int l2)
{
return (lines[l2].b - lines[l1].b)*1.0 / (lines[l1].k - lines[l2].k);
}
int main()
{
int l1, l2;
double x1,x2;
cin >> n;
cin >> l1 >> x1 >> l2 >> x2;
//注意数组是从0开始的
l1--;l2--;
for (int i = 0; i < n; i++)
{
scanf("%d%d", &lines[i].k, &lines[i].b);
}
sx = x1;
ex = x2;
//特判ans=0
if (l1 == l2 && x1 <= x2)
{
cout << 0;
return 0;
}
//特判ans=1
if (lines[l1].k != lines[l2].k)
{
double cx = getCrossX(l1, l2);
if (sx <= cx && ex >= cx)
{
cout << 1;
return 0;
}
}else if (lines[l1].b==lines[l2].b){
if (sx<=ex){
cout<<1;
return 0;
}else{
cout<<-1;
return 0;
}
}
//ans=2枚举过渡线
for (int i = 0; i < n; i++)
if (i != l1 && i != l2)
{
if (lines[l1].k != lines[i].k && lines[i].k != lines[l2].k)
{
double cx1 = getCrossX(l1, i);
double cx2 = getCrossX(i, l2);
if (cx1 <= cx2 && x1 <= cx1 && x2 >= cx2)
{
cout << 2;
return 0;
}
}
}
cout << -1;
}