图论之SPFA

图论之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
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(headint 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].vif(!vis[tmp])
                {
                    vis[tmp]=1;
                    q[++tail]=tmp;
                }
            }
        }
    }
    int num=0;
    for(int i=1;i<=n;i++)
    {
        num+=dis[cow[i]];
    }
    if(numint 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<return 0;
}

你可能感兴趣的:(新しいスタート)