#2018河南省ACMH题 Information Transmission-3 (最短路 + 计算几何)

H. Information Transmission-3                          Time Limit: 2000MS  There is n bases in a certain area,  numbered 1, 2,. .. .. , n,  the location of  base i  is represented by coordinates (xi, yi).  Dr. Kong is at point (x1, y1), he must send an information to point (xn, yn). Because of the insecurity of the network,  he decided to drive the information in person. When he is ready to leave, he find that there is something wrong with the steering wheel of his car. The steering wheel can only turn right and can not turn left.

 

All roads in the area are known . If there is a road from base i to base j, the path length of the road is calculated from the coordinates sqrt((xi-xj)2 +(yi-yj)2) ,  assuming that all roads are two-way.  At first, Dr. Kong may choose any road to set off  from base 1. Once he leaves, he can only go straight or turn right at a given coordinate point.  For faster transmission of information , Can you help Dr. Kong design a shortest path from Base 1 to Base n without turning left on the steering wheel?

Input

The first line of the input contains one integer T, which is the number of  test cases (1<=T<=5).  Each test case specifity:

* Line 1:            n  m     n bases, m roads    ( 1 ≤ n≤ 100, 1 ≤ m≤ 200  )

* Line 2~n+1:       xi  yi     the location of  base i  ( 2 integers, 0 xi , y i ≤ 1000 )

    * Line n+2~n+m+1:  ik  jk     there is a road from base ik to base jk

Output

For each test case generate a single line: a real number, the shortest path from Base 1 to Base n without turning left on the steering wheel.  accurate to 2 decimal places.

 

Sample  Input

Sample  Output

1

5 6

10 10

10 5

30 5

12 30

15 0

1 2

2 5

3 5

1 3

1 4

4 5

36.43

题目大意 :有N个地点, 从1出发到N, 每次只能直走或者往右走 (极坐标下的顺时针), 输出1到 N的最短路

思路 : 只能靠右走, 可以利用向量来做, 如果两个向量 a 和 b的 叉积 < 0, 数目a向量 在b向量的逆时针方向上, 逆时针也就是题目所说的方向盘必须直打或者往右打。 所以在跑最短路的时候可以维护上一个走过的点和当前的点, 如果这两个点和下一个点满足上述关系, 并且有更短的路可以走, 就更新, 由于点1没有上一个点, 所以把和1相连的所有点全部加入队列, 这样1就成了他们的上一个点, 再把1初始化一下, 就解决了

Accepted code

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;

#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define MEM(x, b) memset(x, b, sizeof(x))
#define lowbit(x) ((x) & (-x))
#define P2(x) ((x) * (x))

typedef long long ll;
const int MOD = 1e9 + 7;
const int MAXN = 1e5 + 10;
const int INF = 0x3f3f3f3f;
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }

struct Edge
{
	int v, next;
	double w;
}e[MAXN << 1];
struct node
{
	int last, id; double w;
	bool operator < (const node &oth) const
	{
		return w > oth.w;
	}
}mid;
struct point
{
	double x, y;
}p[MAXN];
int head[MAXN], n, m, cnt, T;
double dis[MAXN];
bool vis[MAXN];
void init() {
	MEM(head, -1); cnt = 0;
}
void add(int from, int to, double wi) {
	e[++cnt].v = to;
	e[cnt].w = wi;
	e[cnt].next = head[from];
	head[from] = cnt;
}
double Cross(point a, point b, point c) {
	return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); // 叉积
}
void dijkstra(int u) {
	priority_queue <node> q;
	for (int i = 1; i <= n; i++) dis[i] = INF * 1.0, vis[i] = 0;
	for (int i = head[1]; i != -1; i = e[i].next)
		q.push({ 1, e[i].v, e[i].w }), dis[e[i].v] = e[i].w; // 与1相连加入队列
	vis[1] = 1; dis[1] = 0;  // 1不要了
	while (!q.empty()) {
		mid = q.top();
		q.pop();
		int ans = mid.id, last = mid.last;
		if (vis[ans] || dis[ans] != mid.w) continue;
		vis[ans] = 1;
		for (int i = head[ans]; i != -1; i = e[i].next) {
			int vi = e[i].v;
			double tmp = Cross(p[last], p[ans], p[vi]); // 叉积小于等于0
			if (tmp <= 0 && dis[vi] > dis[ans] + e[i].w) {
				dis[vi] = dis[ans] + e[i].w;
				q.push({ ans, vi, dis[vi] });
			}
		}
	}
}

int main()
{
	cin >> T;
	while (T--) {
		sc("%d %d", &n, &m); init();
		for (int i = 1; i <= n; i++) sc("%lf %lf", &p[i].x, &p[i].y);
		for (int i = 0; i < m; i++) {
			int ui, vi;
			sc("%d %d", &ui, &vi);
			double tmp = sqrt(P2(p[ui].x - p[vi].x) + P2(p[ui].y - p[vi].y));
			add(ui, vi, tmp); add(vi, ui, tmp);
		}
		dijkstra(1);
		printf("%.2f\n", dis[n]);
	}
	return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值