Single-source shortest path problem: SPFA vs. Dijkstra

36 篇文章 0 订阅
7 篇文章 0 订阅

Use USACO [3_2_butter] as an example

SPFA is an improvement of the Bellman-Ford algorithm, check the corresponding wikipedia page

1. worst case: same complexity as Bellman-Ford O(VE)

average performance: O(E), or O(kE) where k is about 2

2. able to handle negative-weight edges

3. two optimization techniques: SLF & LLL


graph storage: adjacent list + weight matrix


algorithm and result:

(1) SPFA (STL queue, no optimization)

 
   Test 1: TEST OK [0.011 secs, 8348 KB]
   Test 2: TEST OK [0.000 secs, 8348 KB]
   Test 3: TEST OK [0.011 secs, 8348 KB]
   Test 4: TEST OK [0.011 secs, 8348 KB]
   Test 5: TEST OK [0.011 secs, 8348 KB]
   Test 6: TEST OK [0.032 secs, 8348 KB]
   Test 7: TEST OK [0.076 secs, 8348 KB]
   Test 8: TEST OK [0.119 secs, 8348 KB]
   Test 9: TEST OK [0.184 secs, 8348 KB]
   Test 10: TEST OK [0.184 secs, 8348 KB]

(2) Dijkstra + STL priority queue

 
   Test 1: TEST OK [0.000 secs, 8348 KB]
   Test 2: TEST OK [0.000 secs, 8348 KB]
   Test 3: TEST OK [0.011 secs, 8348 KB]
   Test 4: TEST OK [0.011 secs, 8348 KB]
   Test 5: TEST OK [0.022 secs, 8348 KB]
   Test 6: TEST OK [0.065 secs, 8348 KB]
   Test 7: TEST OK [0.119 secs, 8348 KB]
   Test 8: TEST OK [0.227 secs, 8348 KB]
   Test 9: TEST OK [0.389 secs, 8348 KB]
   Test 10: TEST OK [0.367 secs, 8348 KB]


source  code:

(1) Dijkstra

#include <cstdio>
#include <climits>
#include <queue>

using namespace std;

int g[800][800],adjlst[800][800],deg[800];

int main()
{
        freopen("butter.in","r",stdin);
        freopen("butter.out","w",stdout);
        int c,n,m,a[500],b[800]={0};
        scanf("%d%d%d",&c,&n,&m);
        for(int i=0;i<c;i++)
        {
                scanf("%d",&a[i]);
                a[i]--;
                b[a[i]]++;
        }
        for(int i=0;i<n;i++)
                for(int j=0;j<n;j++)
                        g[i][j]=1000000;
        for(int i=0;i<m;i++)
        {
                int s,t,w;
                scanf("%d%d%d",&s,&t,&w);
                s--,t--;
                g[s][t]=g[t][s]=w;
                adjlst[s][deg[s]++]=t;
                adjlst[t][deg[t]++]=s;
        }
        for(int i=0;i<n;i++)
                g[i][i]=0;
        int ans=INT_MAX,sum;
        for(int i=0;i<n;i++)
        {
                int cnt=b[i];
                bool vst[800]={0};
                vst[i]=1;
                int dst[800];
                priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
                for(int j=0;j<n;j++)
                {
                        dst[j]=g[i][j];
                        q.push(make_pair(dst[j],j));
                }
                while(cnt<c)
                {
                        int mindst=q.top().first,idx=q.top().second;
                        q.pop();
                        if(vst[idx])
                                continue;
                        if(mindst>=INT_MAX)
                                break;
                        vst[idx]=1;
                        cnt+=b[idx];
                        for(int j=0;j<deg[idx];j++)
                                if(!vst[adjlst[idx][j]] && dst[adjlst[idx][j]]>mindst+g[idx][adjlst[idx][j]])
                                {
                                        dst[adjlst[idx][j]]=mindst+g[idx][adjlst[idx][j]];
                                        q.push(make_pair(dst[adjlst[idx][j]],adjlst[idx][j]));
                                }
                }
                if(cnt<c)
                        continue;
                sum=0;
                for(int i=0;i<c;i++)
                        sum+=dst[a[i]];
                if(sum<ans)
                        ans=sum;
        }
        printf("%d\n",ans);
        return 0;
}

(2) SPFA

#include <cstdio>
#include <climits>
#include <queue>

using namespace std;

int g[800][800],adjlst[800][800],deg[800];

int main()
{
        freopen("butter.in","r",stdin);
        freopen("butter.out","w",stdout);
        int c,n,m,a[500],b[800]={0};
        scanf("%d%d%d",&c,&n,&m);
        for(int i=0;i<c;i++)
        {
                scanf("%d",&a[i]);
                a[i]--;
                b[a[i]]++;
        }
        for(int i=0;i<n;i++)
                for(int j=0;j<n;j++)
                        g[i][j]=1000000;
        for(int i=0;i<m;i++)
        {
                int s,t,w;
                scanf("%d%d%d",&s,&t,&w);
                s--,t--;
                g[s][t]=g[t][s]=w;
                adjlst[s][deg[s]++]=t;
                adjlst[t][deg[t]++]=s;
        }
        for(int i=0;i<n;i++)
                g[i][i]=0;
        int ans=INT_MAX;
        for(int i=0;i<n;i++)
        {
		int dst[800];
		for(int j=0;j<n;j++)
			dst[j]=INT_MAX;
		dst[i]=0;
		queue<int> q;
		q.push(i);
		bool inq[800]={0};
		inq[i]=1;
		while(!q.empty())
		{
			int u=q.front();
			q.pop();
			for(int j=0;j<deg[u];j++)
			{
				int v=adjlst[u][j];
				if(dst[u]+g[u][v]<dst[v])
				{
					dst[v]=dst[u]+g[u][v];
					if(!inq[v])
						q.push(v);
				}
			}
		}
                int sum=0;
                for(int i=0;i<c;i++)
                        sum+=dst[a[i]];
                if(sum<ans)
                        ans=sum;
        }
        printf("%d\n",ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值