用鄰接表實現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++;
}


發佈了47 篇原創文章 · 獲贊 6 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章