地杰斯特拉算法【模板】
地杰斯特拉算法步骤:
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;
}