链式前向星

#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),(51for(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; 
}

 

 

posted @ 2020-05-04 21:16  INFP  阅读(135)  评论(0编辑  收藏  举报