链式前向星
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int N=1e4+5; int head[N];//链式地址 int cnt=0;//边的下标 struct node{ int from;//表示与第cnt条边同起点的上一条边的储存位置 int to; int w; }edge[N]; void add(int u,int v,int w){ edge[cnt].w=w;//第cnt条边的权值是w edge[cnt].to=v;//第cnt条边的终点是v edge[cnt].from=head[u];//head[i]表示以i起点的最后一条边的储存位置 head[u]=cnt++;//head[]; } int main(){ int n,m; scanf("%d%d",&n,&m); memset(head,0,sizeof(head)); while(m--){ int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); } int start; scanf("%d",&start); for(int i=head[start];i!=0;i=edge[i].from){//输出某个指定结点的连接情况 cout<<start<<"->"<<edge[i].to<<" "<<edge[i].w<<endl; } return 0; }
邻接表
void add(int x,int y,int z){ ver[tot++]=y;//ver存储的每条边终点 edge[tot]=z;//边权 next[tot]=head[x];// head[x]=tot;//head理解从x出发的一个集合 可以根据它找所有边 } head 1 --head[1]=1--> ver[1]=2-->next[1]=0; 2 --head[2]=3--> ver[3]=5-->ver[2]=3-->next[2]=0; 3 --head[3]=4--> ver[4]=5-->next[4]=0; 4 --head[4]=0-->; 5 --head[5]=6--> ver[6]=1-->next[6]=5-->ver[5]=4-->next[5]=0; 插入(1,2),(2,3),(2,5),(3,5),(5,4),(5,1) for(int i=head[x];i;i=next[i]){ int y=ver[i],z=edge[i]; //找出了一条(x,y)有向边,权值为c } ver[i]是i条边的终点,ver[1 xor i]为i起点
//SPFA #include<cstdio> using namespace std; int dis[500010],n,m,f,g,w,t=1,s,q[200000],h,st[500010],tot; bool vis[100010]; /* st[i]表示到达i点的最后一条边的编号; dis[i]表示从起点到i点目前为止的最短距离; vis[i]=true表示点i在队列里; vis[i]=false表示点i不在队列里; 数组q是队列; h是指队列的头指针,t是指队列的尾指针; */ struct node //不开结构体,变量有点乱,所以开结构体; { int to;//这条边连接的终点; int v;//这条边的长度; int last;//前一条边; }e[500010]; void add(int from,int to,int val) /* val表示传入的这条边的权值; from表示传入的这条边的起点; to表示传入的这条边的终点; */ { tot++;//表示当前这条边的编号; e[tot].to=to;//更新当前这条边的终点; e[tot].v=val;//更新当前这条边的长度(权); e[tot].last=st[from]; /* e[tot].last表示的是当前读入的这条边的上一条边; st[from]表示的是 到当前读入的边为止(不包括这条边) 的上一条边的序号; */ st[from]=tot;//更新为 当前读入的边为止(包括这条边) 的上一条边的序号; } void SPFA()//核心最短路; { while(h<=t)//队列不为空; { h++; int u=q[h];//取出队首 vis[u]=0;//队首出队 for(int i=st[u]; i!=0; i=e[i].last) /* st[u]是指可以到达点u的上一条边,如果存在st[u](也就是st[u]不为0,因为0是初始值), 说明有一条边可以到达点u。所以i变成st[u]。e[i].last是指可以到达st[u]这条边的起点的边的编号 */ { int v=e[i].to; if(dis[v]>dis[u]+e[i].v) /* 如果从起点到v的距离大于从起点到点i,再从点i到点u,再从点u到点v的距离,更新从起点 到点v的最短路; */ { dis[v]=dis[u]+e[i].v; if(vis[v]==0)//没有入过队就入队; { vis[v]=1;//标志改为1,表示已经入队; t++; q[t]=v; } } } } } int main() //主程序; { scanf("%d %d %d",&n,&m,&s); for(int i=1;i<=m;i++) { scanf("%d %d %d",&f,&g,&w);//输入这条边的起点f,终点g和长度w; add(f,g,w);//建图; } for(int i=1;i<=n;i++)//因为题目要我们求一个点到其余点的最短路; dis[i]=2147483647;//所以初始化全部赋为int的最大值; dis[s]=0;//起点到本身的的距离为0; q[t]=s;//起点入队; vis[s]=true;//标志改为true表示起点已入队; SPFA(); //运行最短路; for(int i=1;i<=n;i++)//循环输出答案; printf("%d ",dis[i]); return 0; }