用邻接表实现spfa

邻接表的存储方式如下



注意:我所说的节点和点表示的意思是有区别的!!

先用一个list[]存所有的点。

即:

1.第一列的每一个点都在list中对应一个位置。

2.把每一个在list中的点看做源点,如图(横向看),每一源点都有若干个点与它连接,表示它可直接达到的点。如v1->0,v1->2,可表示所谓的”路“。横着也是一个链表!

3.横向链表中以NULL为结束标志

邻接表的实现想了好长时间,终于想出了我认为还可以的方法,会在代码中说明。

以hdu 2544 最短路为例(当然此题也可以用其他方法来做)

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct node//用此结构表示横向链表中的所有节点
{
    node * next;//表示下一个与源点相连的节点
    int p;//表示这个节点的位置,就是与源点相连的那个点;
    int distance;//表示这条路径的权值
}Node[50000+10];//有多少条有效路径就会有多少个节点(双向*2)
int k;//记录用了多少个节点
node *list[100+10];//记录源点后的第一个节点
int dis[100+10];//下面三个数组都是spfa中要用的,不多说
int vis[100+10];
int q[1000];
void func(node* &temp_,int p,int d)//建邻接表,注意我传的是引用,以便修改list[a]的值
{
    node*temp;
    if(temp_==NULL)//如果一开始源点没有与他相连的节点
    {
        temp_=&Node[k++];
        temp=temp_;//<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">由于传的是引用,</span>防止再次修改temp_
    }
    else
    {
        temp=temp_;//由于传的是引用,防止修改temp_,
        while(temp->next!=NULL)
        {
            if(temp->p==p)
            {
                int t=temp->distance;
                    temp->distance=(t>d?d:t);
                return ;
            }
            temp=temp->next;
        }
        temp->next=&Node[k++];//这点我被坑了好长时间,一定要修改temp->next的值,不然会断链的
        temp=temp->next;
    }
    temp->distance=d;
    temp->next=NULL;
    temp->p=p;
}
int spfa(int s,int v)//跟bfs一样,就是点可以重复入队
{
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[s]=0;
    q[0]=s;
    vis[s]=1;
    int front=0,rear=1;
    while(front<rear)
    {
        int temp1=q[front++];
        node *temp2=list[temp1];
        while(temp2!=NULL)
        {
            if(dis[temp2->p]>dis[temp1]+temp2->distance)
            {
                dis[temp2->p]=dis[temp1]+temp2->distance;
                if(!vis[temp2->p])
                {
                    q[rear++]=temp2->p;
                    vis[temp2->p]=1;
                }
            }
            temp2=temp2->next;
        }
        vis[temp1]=0;
    }
    return dis[v];
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(!n&&!m)
            break;
        k=0;
        for(int i=1;i<=n;i++)
            list[i]=NULL;
        while(m--)
        {
            int a,b,v;
            scanf("%d%d%d",&a,&b,&v);
            func(list[a],b,v);
            func(list[b],a,v);
        }
        int ans=spfa(1,n);
        /*
        for(int i=1;i<=n;i++)
        {
            cout<<"from "<<i<<" to"<<endl;
            node *temp=list[i];
            while(temp!=NULL)
            {
                cout<<"->";
                cout<<temp->p<<ends<<temp->distance<<endl;
                temp=temp->next;
            }
        }
        */
        cout<<ans<<endl;
    }
    return 0;
}


由小白想到的简洁代码

struct Edge
{
    int next;
    int gohere;
    int dis;
}edge[3000];
int p;//初始化为 0
int head[50];//初始化为 -1
void addedge(int a,int b,int dis)//a到b的路权为dis
{
    edge[p].next=head[a];
    edge[p].gohere=b;
    edge[p].dis=dis;
    head[a]=p++;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值