链接:https://ac.nowcoder.com/acm/contest/7501/B
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
Given a maze of size n×mn\times mn×m, whose lower-left corner is (0,0)(0, 0)_{}(0,0) while upper-right corner is (n,m)(n, m)_{}(n,m). And there are kk_{}k segment walls in the maze. One cannot cross the walls but can touch them or walk along them. Now a MI robot is assigned to go from (X1,Y1)(X_1, Y_1)(X1,Y1) to (X2,Y2)(X_2, Y_2)(X2,Y2), as an intelligent robot, MI robot will automatically determine the shortest valid path and go along it. Print the length of the shortest valid path between (X1,Y1)(X_1, Y_1)(X1,Y1) and (X2,Y2)(X_2, Y_2)(X2,Y2).
输入描述:
The first line contains three integers n,m,k (1≤n,m≤10000,0≤k≤300)n,m,k~(1\le n,m \le 10000, 0\le k\le 300)n,m,k (1≤n,m≤10000,0≤k≤300), denoting the size of the maze and the number of walls respectively.
Following k lines each contains four integers x1,y1,x2,y2 (1≤x1,x2<n,1≤y1,y2<m)x_1,y_1,x_2,y_2~(1\le x_1,x_2 < n, 1\le y_1,y_2 < m)x1,y1,x2,y2 (1≤x1,x2<n,1≤y1,y2<m), denoting a segment wall (x1,y1)−(x2,y2)(x_1,y_1) - (x_2,y_2)(x1,y1)−(x2,y2).
The next line contains four integers X1,Y1,X2,Y2 (0≤X1,X2≤n,0≤Y1,Y2≤m)X_1,Y_1,X_2,Y_2~(0\le X_1,X_2 \le n, 0\le Y_1,Y_2\le m)X1,Y1,X2,Y2 (0≤X1,X2≤n,0≤Y1,Y2≤m), denoting the two given points.
It's guaranteed that no two segment walls share common points, and that no segment wall covers (X1,Y1)(X_1, Y_1)(X1,Y1) or (X2,Y2)(X_2, Y_2)(X2,Y2), and that either X1≠X2X_1 \neq X_2X1=X2 or Y1≠Y2Y_1 \neq Y_2Y1=Y2.
输出描述:
Only one line containing a real number with four decimal places after the decimal point, denoting the answer.
It's guaranteed that the fifth decimal place after the decimal point is neither 4 nor 5.
示例1
输入
6 3 2
1 1 3 1
2 2 5 2
3 0 3 3
输出
3.8284
题意: k 堵墙(墙是线段),人不可穿墙但可以沿墙走,求起点到终点的最短路
思路:图中有用的点只有起点、终点、每堵墙的两个端点,枚举两个点,判断它们有没有被墙隔开,如果没有就连边,跑最短路
#include <cstdio>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
#include <iostream>
using namespace std;
const double eps = 1e-8;
const int inf = 0x3f3f3f3f;
const int N = 620;
int n, m, k, totn;
int sign(double x)//判断符号可用
{
if(fabs(x) <= eps) return 0;
if(x > 0) return 1;
else return -1;
}
struct Point {
double x, y;
Point(){}
//定义运算
Point(double _x,double _y){x = _x;y = _y;}
Point operator + (const Point &b)const{
return Point(x+b.x,y+b.y);
}
Point operator - (const Point &b)const{
return Point(x-b.x,y-b.y);
}
Point operator * (const double &k)const{//乘常数
return Point(x*k,y*k);
}
Point operator / (const double &k)const{
return Point(x/k,y/k);
}
//点的叉积和点积都是数
//点积
double operator * (const Point &b)const{
return x*b.x+y*b.y;
}
//叉积
double operator ^ (const Point &b)const{
return x*b.y-y*b.x;
}
Point base()const{//向量的方向向量
if(sign(x) == -1 ||(sign(x) == 0 && sign(y) == -1))
return Point(-x,-y);
return *this;
}
bool operator < (const Point &a)const{//重载小于号 让map可以存向量 不然不可以直接存向量
Point p1 = base(),p2 = a.base();
return p1.x*p2.y < p2.y*p1.y;
}
double powlen(){return x*x+y*y;};
double len(){return sqrt(powlen());}
} point[N];
double dis(Point a, Point b) {
return 1.0 * sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
struct Wall {
int a, b;
} wall[N];
int src, des, head[N];
double dist[N];
bool vis[N];
int tot;
struct Node {
double l;
int u, v, next; ///起点 终点 长度 与该边同起点的上一条边的储存位置
} edge[750000];
struct A {
int pos;
double cost;
bool operator < (const A &a) const {
return cost > a.cost;
}
};
void addedge(int x, int y, double z) {
edge[tot].u = x;
edge[tot].v = y;
edge[tot].l = z;
edge[tot].next = head[x];
head[x] = tot++;
}
double dijk(int src, int des) {
for(int i = 0; i < N; ++i) dist[i] = 1.0 * inf;
memset(vis, 0, sizeof(vis));
priority_queue<A>q;
dist[src] = 0;
A now;
now.cost = 0;
now.pos = src;
q.push(now);
while(!q.empty()) {
now = q.top();
q.pop();
if(vis[now.pos])
continue;
vis[now.pos] = 1;
for(int i = head[now.pos]; ~i; i = edge[i].next) //遍历以该点为顶点的所有边
{
int to = edge[i].v; //to = 这条边的终点
if(!vis[to] && dist[to] > edge[i].l + dist[edge[i].u]) //to没有更新过且目前源点到to的距离 > 该边的长度 + 源点到该边起点的距离
{
dist[to] = dist[edge[i].u] + edge[i].l; //更新
now.cost = dist[to];
now.pos = to;
q.push(now);
}
}
}
return dist[des];
}
bool check(Point a, Point b, Point c, Point d) {
return ((c - a) ^ (b - a)) * ((d - a) ^ (b - a)) < 0 &&
((a - c) ^ (d - c)) * ((b - c) ^ (d - c)) < 0;
}
int main() {
int x1, x2, y1, y2;
totn = 0, tot = 0;
memset(head, -1, sizeof(head));
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= k; ++i) {
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
point[++totn].x = 1.0 * x1, point[totn].y = 1.0 * y1;
wall[i].a = totn;
point[++totn].x = 1.0 * x2, point[totn].y = 1.0 * y2;
wall[i].b = totn;
}
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
point[++totn].x = 1.0 * x1, point[totn].y = 1.0 * y1;
src = totn;
point[++totn].x = 1.0 * x2, point[totn].y = 1.0 * y2;
des = totn;
for(int i = 1; i <= totn; ++i) {
for(int j = i + 1; j <= totn; ++j) {
bool flag = 0;
for(int p = 1; p <= k; ++p) {
if(check(point[wall[p].a], point[wall[p].b], point[i], point[j])) {
flag = 1;
break;
}
}
if(!flag) {
double tmp = dis(point[i], point[j]);
// cout<<point[i].x<<' '<<point[i].y<<' '<<point[j].x<<' '<<point[j].y<< ' '<<tmp<<'\n';
addedge(i, j, tmp);
addedge(j, i, tmp);
}
}
}
printf("%.4f\n", dijk(src, des));
return 0;
}