图论之SPFA

来源:互联网 发布:2016年网络流行关键词 编辑:程序博客网 时间:2024/06/05 00:52

图论之SPFA

First:
在Bellman-ford算法中,每次都要检查所有的边。这个看起来比较浪费,对于边(x,y),如果上一次dis[x]没有改变,则本次的检查显然是多余的。

Next:
而所谓SPFA,就是在Bellman-ford算法的基础上,对迭代进行了改进。

Then:
我们只要每次都从上次刚被“松驰”过的点x,来看看x能不能松驰其它点即可完成优化。
那么如何实现呢?
SPFA算法中用BFS中的队列来存放刚被“松驰”过的点。由于顶点个数为|V|,队列如果用数组的话显然要用“循环队列”使用空间。
SPFA在形式上和宽度优先搜索非常类似,不同的是宽度优先搜索中一个点出了队列就不可能重新进入队列,但是SPFA中一个点可能在出队列之后再次被放入队列,也就是一个点改进过其它的点之后,过了一段时间可能本身会再次被改进,于是再次用来改进其它的点,这样反复迭代下去。
这一点也是SPFA算法最重要的一个点,也正是这一点让SPFA能够实现求最短路。
上个伪代码:
SP_SPFA(G, s) //求单源s到其它点的最短距离
for i=1 to n do
dis[i] =∞;vis[i] =false; // 初始化每点到s距离,不在队列
dis[s] 0; //将dis[s]设为0
vis[s] =true; count = 1; //s放入队列
head = 0; tail = 0; q[0]=s; //队列头尾指针
while (count>0) do
v = q[head]; //队头节点v
for 每条边(v,i) //与v相连的每一条边
if( dis【v]+len【v][i]小于dis[i]) //不满足三角形性质
dis【i] =dis【v]+len【v][i]; //松驰dis[i]
if (vis[i] = false) //不在队列,则加入队列
vis[i] = true; count+1;
tail+1; q[tail] = i;
vis[v] =false;head+1;count-1; //v出队列

And Then:
上例题:香甜的黄油 洛谷P1828
题目描述
农夫John发现做出全威斯康辛州最甜的黄油的方法:糖。把糖放在一片牧场上,他知道N(1<=N<=500)只奶牛会过来舔它,这样就能做出能卖好价钱的超甜黄油。当然,他将付出额外的费用在奶牛上。 农夫John很狡猾。像以前的Pavlov,他知道他可以训练这些奶牛,让它们在听到铃声时去一个特定的牧场。他打算将糖放在那里然后下午发出铃声,以至他可以在晚上挤奶。 农夫John知道每只奶牛都在各自喜欢的牧场(一个牧场不一定只有一头牛)。给出各头牛在的牧场和牧场间的路线,找出使所有牛到达的路程和最短的牧场(他将把糖放在那)

输入格式
第一行: 三个数:奶牛数N,牧场数(2<=P<=800),牧场间道路数C(1<=C<=1450) 第二行到第N+1行: 1到N头奶牛所在的牧场号 第N+2行到第N+C+1行: 每行有三个数:相连的牧场A、B,两牧场间距离(1<=D<=255),当然,连接是双向的

输出格式
一行 输出奶牛必须行走的最小的距离和

样例数据
input

3 4 5
2
3
4
1 2 1
1 3 5
2 3 7
2 4 3
3 4 5
output

8
{说明: 放在4号牧场最优}

数据规模与约定
时间限制:1s1s
空间限制:256MB

上代码:

#include<bits/stdc++.h>using namespace std;struct my{    int v,y,next;}e[20000];int a[20000],len=0,cow[1000];int n,p,c;void insert(int xx,int yy,int vv){    e[++len].next=a[xx];    a[xx]=len;    e[len].y=yy;    e[len].v=vv;}int dis[10000],vis[10000],q[10000],minn=10000000;void spfa(int st){    memset(dis,10,sizeof(dis));    memset(vis,0,sizeof(vis));    dis[st]=0;    vis[st]=1;    q[1]=st;    int head=0,tail=1;    while(head<tail)    {        int tn=q[++head];        vis[tn]=0;        int te=a[tn];        for(int i=te;i;i=e[i].next)        {            int tmp=e[i].y;            if(dis[tn]+e[i].v<dis[tmp])            {                dis[tmp]=dis[tn]+e[i].v;                if(!vis[tmp])                {                    vis[tmp]=1;                    q[++tail]=tmp;                }            }        }    }    int num=0;    for(int i=1;i<=n;i++)    {        num+=dis[cow[i]];    }    if(num<minn) minn=num;}int main(){    cin>>n>>p>>c;    for(int i=1;i<=n;i++)        cin>>cow[i];    int x,y,v;    for(int i=1;i<=c;i++)    {        cin>>x>>y>>v;        insert(x,y,v);        insert(y,x,v);    }    for(int i=1;i<=p;i++)    spfa(i);    cout<<minn;    return 0;}
原创粉丝点击