2020ICPC·小米 网络选拔赛第一场 B-Intelligent Robot (叉积判相交+最短路)

在这里插入图片描述
题意:给定你k条线段的端点坐标,这k条线段相当于k道墙,小米机器人无法穿过每堵墙,但是可以沿着墙行走,然后给定你一个起始点坐标和终点坐标,问你从起点到终点最短的距离是多少即可。

思路:很明显假如没有墙的限制,那就是个裸的最短路,加上了墙的限制,就是对我们能够建边的点加上了限制。在这个题中,我们只需要把起点和终点再加上每条线段的端点放入一个vector中,然后枚举两个点形成的线段和其他所有的线段墙,只要他们之间不存在交点或者交点在端点处,这时枚举的两个点就可以建边,建完边后跑一遍最短路即可以解决问题了。
判断两条线段有没有交点,很明显我们要用叉积来判断。
加点的时候先加起点,最后加终点,并且每条线段的两个端点之间是一定要建上边的。

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const double eps = 1e-9;
const int MAXN = 1007;
const int inf = 0x3f3f3f3f;

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;
	}
	double powlen(){return x*x+y*y;};

	double len(){return sqrt(powlen());}
};

double cross(Point a,Point b){//叉积
	return a.x*b.y-a.y*b.x;
}

double dot(Point a,Point b){//点积
	return a.x*b.x+a.y*b.y;
}

double dis(Point a,Point b){
	return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}

struct Line{
	Point a,b;
    Line(){};
	Line(Point _a,Point _b){a = _a;b = _b;}
}line[MAXN];

int head[MAXN],cnt;
struct node{
	int next,to;
	double w;
}edge[MAXN*MAXN];

void addedge(int u,int v,double w){ edge[++cnt].to = v;edge[cnt].w =  w;edge[cnt].next = head[u];head[u] = cnt; }

bool check(Line l1,Line l2){
	Point AB = l1.b - l1.a;
	Point AD = l2.b - l1.a;
	Point AC = l2.a - l1.a;

	Point CD = l2.b - l2.a;
	Point CA = l1.a - l2.a;
	Point CB = l1.b - l2.a;

	if(sign(cross(AB,AC)) * sign(cross(AB,AD)) < 0 && sign(cross(CD,CA)) * sign(cross(CD,CB)) < 0 )
		return true;
	return false;
}

double d[MAXN];int vis[MAXN];
void spfa(int s){
	d[s] = 0;
	vis[s] = 1;
	for(int i = 1;i < MAXN;i ++) d[i] = (double)inf;
	queue<int>q;
	q.push(s);
	while(!q.empty()){
		int u = q.front();
		q.pop();
		vis[u] = 0;
		for(int i = head[u];i;i = edge[i].next){
			int v = edge[i].to;
			if(d[v] > d[u] + edge[i].w){
				d[v] = d[u] + edge[i].w;
				if(!vis[v]){
					vis[v] = 1;
					q.push(v);
				}
			}
		}
	}
}

vector<Point>v;

int main()
{
	int n,m,k;
	scanf("%d%d%d",&n,&m,&k);
	int tot = 0;
	for(int i = 1;i <= k;i ++){
		Point p1,p2;
		scanf("%lf%lf%lf%lf",&p1.x,&p1.y,&p2.x,&p2.y);
		line[i].a = p1,line[i].b = p2;
	}
	Point st,ed;
	scanf("%lf%lf%lf%lf",&st.x,&st.y,&ed.x,&ed.y);
	v.push_back(st);
	for(int i = 1;i <= k;i ++){
		v.push_back(line[i].a);
		v.push_back(line[i].b);
		int from = v.size()-2,to = v.size()-1;
		double len = dis(v[from],v[to]);
		//cout<<"---"<<len<<endl;
		addedge(from,to,len);
		addedge(to,from,len);
	}
	v.push_back(ed);
	for(int i = 0;i < v.size();i ++){
		for(int j = i + 1;j < v.size();j ++){
			Line tmp = Line(v[i],v[j]);
			int flag = 0;
			for(int tt = 1;tt <= k;tt ++){
				if(check(tmp,line[tt])){
					flag = 1;
					break;
				}
			}
			if(!flag){
				addedge(i,j,dis(v[i],v[j]));
				addedge(j,i,dis(v[i],v[j]));
			}
		}
	}
	spfa(0);
	printf("%.4f\n",d[v.size()-1]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值