拯救007 迪杰斯特拉最短路解决

本文介绍了一种使用迪杰斯特拉算法解决特定路径寻找问题的方法。通过构建图结构并运用该算法找到从起点到边界点的最短路径。文章详细展示了算法实现过程,包括节点与边的定义、距离计算、边界条件判断等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路:直接建图,走一遍迪杰斯特拉,最后比较一下能到达边界点的最短路径就可以了。正确性还没具体验证,不过样例过了。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
#include<stack> 
#define inf 0x3f3f3f3f
#define debug cout<<"debug"<<endl
using namespace std;
const int maxn=1e4+50;
vector<int> g[maxn];
vector<int> ok_node;
int n,d,diss[maxn],p[maxn],ans,ans_node;
bool vis[maxn];

struct Node{
	int x,y;
	Node(int xx,int yy):x(xx),y(yy){
	}
	Node(){
	}
}node[maxn];

struct HeapNode{
	int d,u;
	bool operator < (const HeapNode& rhs) const{
		return d>rhs.d;
	} 
};

struct Edge{
	int from,to,dis;
	Edge(int ff,int tt,int dd):from(ff),to(tt),dis(dd){
	} 
};

vector<Edge> edge;

double ok_dis(Node a,Node b){///计算距离
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

bool ok_bound(Node a){///确定边界范围内的点
	if((a.x>=0&&a.x<=d&&a.y>=0&&a.y<=100)||(a.x>=d&&a.x<=100&&a.y>=100-d&&a.y<=100)||(a.x>=100-d&&a.x<=100&&a.y>=0&&a.y<=100-d)||(a.x>=d&&a.x<=100-d&&a.y>=0&&a.y<=d))
	return true;
	return false;
}

void dij(){
	priority_queue<HeapNode> q;
	memset(diss,inf,sizeof(diss));
	diss[0]=0;
	memset(vis,0,sizeof(vis));
	q.push(HeapNode{0,0});
	while(!q.empty()){
		HeapNode temp=q.top();q.pop();
		int uu=temp.u;
		if(vis[uu]) continue;
		vis[uu]=true; 
		for(int i=0;i<g[uu].size();i++){
			Edge &e=edge[g[uu][i]];
			if(diss[e.to]>diss[uu]+e.dis){
				diss[e.to]=diss[uu]+e.dis;
				p[e.to]=uu;
				q.push(HeapNode{diss[e.to],e.to});
			} 
		}
	}
}

int main(){
	while(scanf("%d",&n)!=EOF){
		if(n==-1) break;
		ans=inf;
		memset(node,0,sizeof(node));
		edge.clear(),memset(g,0,sizeof(g)),ok_node.clear();
		scanf("%d",&d);
		node[0].x=50,node[0].y=50;
		if(ok_bound(node[0])) ok_node.push_back(0);///ok_node存放可以到达边界的点
		for(int i=1;i<=n;i++){
			int xx,yy;
			scanf("%d%d",&xx,&yy);
			node[i].x=xx+50,node[i].y=yy+50;
			if(ok_bound(node[i])){
				ok_node.push_back(i);
			}
		}
		if(ok_node.empty()){
			printf("-1\n");continue; 
		}
		for(int i=0;i<=n;i++) 
		for(int j=i+1;j<=n;j++){
			double dis=ok_dis(node[i],node[j]);
			if(!i) dis-=7.5;
			if(dis<=d){
				edge.push_back(Edge(i,j,1));
				g[i].push_back(edge.size()-1);///边编号从0开始 
				edge.push_back(Edge(j,i,1));
				g[j].push_back(edge.size()-1);
			} 
		}
		if(edge.empty()){
			printf("-1\n");continue; 
		} 
		dij();
		for(int i=0;i<ok_node.size();i++){
		int kk=ok_node[i];
		if(diss[kk]<ans)	ans=diss[kk],ans_node=kk;
	}
		stack<int> s;
		int ee=ans_node;
		for(;;){
			if(!diss[ee]) break;
			s.push(ee);
			ee=p[ee];
		}
		printf("%d\n",ans+1);///最后别忘了还要跳到边界上
		while(!s.empty()){
		int temp=s.top();s.pop();
		printf("%d %d\n",node[temp].x-50,node[temp].y-50);			
		}

	}
	return 0;
}




Dijkstra算法 Dijkstra算法的思路是:设有向图G=(V,E),其中,V={v0,v1,…,vn-1},cost[i][j]表示有向边的权值。若不存在有向边,则cost[i][j]的权为无穷大(∞)。数组ds记录从源点到其他各顶点当前的短距离,其初值ds[i]=cost[v][i],从s之外的顶点集合V-S中选一个顶点vu,使ds[u]的值小。于是从源点v到达只通过s中的顶点,把u加入集合s中调整ds中的记录从源点到V-S中每个顶点vj的距离:从原来的ds[j]和ds[u]+cost[u][j]中选择较小的值作为新的ds[j]。重复上述过程,直到s中包含其余各顶点的最短路径 Floyd-warshall算法 Floyd-warshall算法的基本思想是:如果从vi到vj有边,则从vi到vj存在一条长度为cost[i][j]的路径。该路径不一定是最短路径,尚需要进行n次试探。首先考虑路径(vi,v0, vj)是否存在。如果存在,则比较其路径长度。取长度较短者为从vi到vj的中间顶点的序号不大于0的最短路径。假如在路径上再增加一个顶点v1,即如果(vi,…, v1)和(v1,…,v)分别是当前找到的中间顶点的序号不大于0的最短路径,那么,(vi,…, v1,…, vj)就有可能是从vi到vj中间顶点的序号不大于1的最短路径。将它和已经得到的从vi到vj中间顶点的序号不大于0的最短路径相比较,从中选出中间顶点的序号不大于1的最短路径后,在增加一个顶点v2,继续进行试探。依次类推,直至经过n次比较,后求得的必是从vi到vj的最短路径。按此方法,可以同时求得各对顶点间的对段距离。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值