2020ICPC·小米 网络选拔赛第一场 B Intelligent Robot(建图 + 最短路)

链接: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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值