地杰斯特拉算法【模板】

地杰斯特拉算法步骤:
1.找离起点x最近的未讨论过的点k
2.判断经过k点,起点x到其他点的距离是否缩短,如缩短则更新。将k点标记为已讨论。
3.返回第1步,直到所有点都被讨论过
O(n^2):

#include<bits/stdc++.h>
using namespace std;
int map1[101][101],dis[101],n,m;
bool mark[101];
void dij(int x)
{
	int k,i,Min;
	for(i=1;i<=n;i++)
	{
		dis[i]=map1[x][i];
	}
	mark[x]=1;//初始化
	do
	{
		Min=0x7f;
		k=0;
		for(i=1;i<=n;i++)步骤1
		{
			if(mark[i]==0&&dis[i]<Min)
			{
				Min=dis[i];
				k=i;
			}
		}
		if(k==0) break;
		for(i=1;i<=n;i++)//步骤2
		{
			if(dis[i]>dis[k]+map1[k][i])
			{
				dis[i]=dis[k]+map1[k][i];
			}
		}
		mark[k]=1;
	}
	while(k>0);//步骤3
}
int main()
{
	int i,x,y;
	scanf("%d%d",&n,&m);//n个点,m条边
	memset(map1,0x7f,sizeof(map1));//初始化无穷大
	for(i=1;i<=m;i++)
	{
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		map1[a][b]=c;
	}
	scanf("%d%d",&x,&y);//输出从x到y的最短路
	dij(x);
	printf("%d",dis[y]);
	return 0;
}

O(mlogn):

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
int n,m,s,Map[10010],Last[500010],End[500010],Len[500010],Next[500010];//Map【i】表示s(出发点)到i的最短距离 
bool mark[10010];
struct Node//优先队列固定格式 
{
	int Num,dis;//Num是节点编号,dis是起点到该点的距离 
	bool operator<(const Node &a) const
	{
		return a.dis<dis;
	}
};
inline void Dij()
{
	priority_queue<Node> q;//建立优先队列 
	Node temp;
	temp.Num=s;//起始点 
	temp.dis=0;//起始点到自己的距离为0 
	q.push(temp);//放入 
	while(!q.empty())
	{
		int u=q.top().Num;//取出队首的点 
		q.pop();//弹出 
		if(mark[u]==1) continue;//如果被讨论过了继续循环 
		mark[u]=1;//标记 
		for(int i=Last[u];i!=0;i=Next[i])//链式前向星遍历 
		{
			int v=End[i];
			if(mark[v]==0&&Map[v]>Map[u]+Len[i])
			{
				Map[v]=Map[u]+Len[i];
				temp.Num=v;
				temp.dis=Map[v];
				q.push(temp);
			}
		}
	}
}
int main()
{
	memset(Map,0x3f,sizeof(Map));
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		End[i]=y;//End【i】表示第i条边的终点 
		Len[i]=z;//Len【i】表示第i条边的长度 
		Next[i]=Last[x];//Next【i】表示在第i条边的上一条以x为起始点的边 
		Last[x]=i;//Last【i】表示以第i个点为起始点的最后一条边 
		//这种存图方法叫链式前向星 
	}
	Map[s]=0;
	Dij();
	for(int i=1;i<=n;i++)
	{
	    if(Map[i]<1061109567) printf("%d ",Map[i]);
	    else printf("2147483647 ");
	}
	return 0;
}
#include<cstdio>  
#include<iostream>  
#include<algorithm>  
#include<cstring>  
#include<iostream>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<vector>
#include<map>
using namespace std;
int n,m,s1,s2,dis[101];
bool mark[101];
struct Node//固定结构 
{
	int Num,dis;
	bool operator<(const Node &a) const
	{
		return a.dis<dis;
	}
};
struct Map
{
	int _End;
	int _Len;
};
vector<Map> G[101];
inline void Dij()
{
	int t;
	priority_queue<Node> q;
	Node temp;
	temp.Num=s1;
	temp.dis=0;
	q.push(temp);//前面与链式前向星无异 
	while(!q.empty())
	{
		int u=q.top().Num;//取出队首元素 
		q.pop();//弹出 
		if(mark[u]==1) continue;//如果被讨论过了就继续循环 
		mark[u]=1;
		for(int i=0;i<G[u].size();i++)//vector遍历 
		{
			int v=G[u][i]._End;
			int l=G[u][i]._Len;
			if(mark[v]==0&&dis[v]>dis[u]+l)
			{
				dis[v]=dis[u]+l;
				temp.Num=v;
				temp.dis=dis[v];
				q.push(temp);
			}
		}
	}
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(dis,0x3f,sizeof(dis));
    Map Edge;
    for(int i=1;i<=m;i++)
    {
    	int x,y,z;
    	scanf("%d%d%d",&x,&y,&z);
    	Edge._End=y;//第i条边的终点是y 
    	Edge._Len=z;//第i条边的长度是z 
    	G[x].push_back(Edge);//存进
		//这种方法叫vector存图 
	}
	scanf("%d%d",&s1,&s2);
	dis[s1]=0;
	Dij();
	printf("%d",dis[s2]);
    return 0;
}

求最长路:题目https://www.luogu.org/problemnew/show/P1576

#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
int n,m,A,B;
double dis[2010];
bool mark[2010];
struct Node//固定格式:因为最短路里面是从小到大,那么最长路就要反过来,从大到小 
{
	int Num;
	double dis;
	bool operator<(const Node &a) const
	{
		return a.dis>dis;//再次提醒 
	}
};
struct node
{
	int Num;
	double dis;
};
vector<node> G[2010];
inline void Dij()
{
	priority_queue<Node> q;//建立优先队列 
	Node temp;
	temp.Num=A;
	temp.dis=1;
	q.push(temp);//初始化 
	while(!q.empty())
	{
		int u=q.top().Num;//取出队首的元素 
		q.pop();
		if(mark[u]==1) continue;
		mark[u]=1;
		for(int i=0;i<G[u].size();i++)//讨论与队首元素相关的点 
		{
			int v=G[u][i].Num;
			double l=G[u][i].dis;
			if(mark[v]==0&&dis[v]<dis[u]*l)//最长路更新 
			{
				dis[v]=dis[u]*l;
				temp.Num=v;
				temp.dis=dis[v];
				q.push(temp);//入队 
			}
		}
	}
}
int main()
{
	node temp;
	scanf("%d%d",&n,&m);//输入点,边 
	memset(dis,-0x3f,sizeof(dis));//因为是求最长路,所以初始化为负无穷 
	for(int i=1;i<=m;i++)
	{
		int x,y;
		double z;
		scanf("%d%d%lf",&x,&y,&z);//输入一条线的两端以及长度 
		temp.Num=y;
		temp.dis=1-z/100;
		G[x].push_back(temp);
		temp.Num=x;
		G[y].push_back(temp);//双向边,用的vector存图,链式前向星同理 
	}
	scanf("%d%d",&A,&B);//输入起始点,终止点 
	dis[A]=1;//起始点到自己的距离要初始化为1,不能是0,否则等下与之相乘的数就会是0了 
	Dij();//跑 
	printf("%.8lf",100/dis[B]);//输出答案 
	return 0;
}
posted @ 2019-07-05 15:29  最爱丁珰  阅读(32)  评论(0编辑  收藏  举报