Stockbroker Grapevine(AC) Bellman Ford算法

这道题我用的是Bellman Ford算法,用其他的最短路径算法(Floyd、Dijstra)也可。

#include <iostream>
#include <memory.h>

using namespace std;

int weight[101][101];
int dis[101];
int pi[101];
int minTime = 10000;
//最多有 100 * (100-1) 条边,每个边有两个节点
int edgeStack[100 * (100-1) * 2];
//Index 首字母大写,因为 index 在函数库中另有含义    
int Index = 0;                
int vertexNum = 0;
int edgeNum = 0;

void PushEdge(int i, int j)
{
     //注意前后置的 ++ 运算符与 Index 的上限的大小关系,要相应 -2 和 -1
    if (Index <= 100*(100-1)*2-1-1)
    {
        edgeStack[Index++] = j;
        edgeStack[Index++] = i;
    }
}

void PopEdge(int &i, int &j)
{
    if (Index >= 2)
    {
        i = edgeStack[--Index];
        j = edgeStack[--Index];
    }
}

void input()
{
    int p;
    int cost;
    for (int j=1; j<=vertexNum; j++)
    {
        int edge;
        cin >> edge;
        edgeNum += edge;
        for (int i=1; i<=edge; i++)
        {
            cin >> p >> cost;
            weight[j][p] = cost;
            PushEdge(j, p);
        }
    }
}

const int MAX = 10000;
const int NIL = -1;
void Initialize_Single_Source(int s)
{
    for (int i=1; i<=101; i++)
    {
        dis[i] = MAX;
        pi[i] = NIL;
    }
    dis[s] = 0;
}

void Relax(int u, int v)
{
    if (dis[v] > dis[u] + weight[u][v])
    {
        dis[v] = dis[u] + weight[u][v];
        pi[v] = u;
    }
}

bool Bellman_Ford(int s)
{
    Index = edgeNum * 2;        //在每一次调用 Bellman_Ford 时,要记得将 edgeStack 数组下标归末;
    int u, v;
    Initialize_Single_Source(s);
    for (int i=0; i<vertexNum-1; i++)
    {
        for (int j=0; j<edgeNum; j++)
        {
            PopEdge(u, v);
            Relax(u, v);
        }
        Index = edgeNum * 2;      //这里也是
    }
    for (int i=0; i<edgeNum; i++)    //这个循环对这道题来说不是必要的,但为了理解算法导论的算法,就把负环路检测的代码加上了
    {
        PopEdge(u, v);
        if (dis[v] > dis[u] + weight[u][v])
        {
            return false;
        }
    }
    return true;
}

int SelectMax(int dist[101])
{
    int max = 0;
    for (int i=1; i<=vertexNum; i++)   //注意这里是 vertexNum 不是 edgeNum,因为 dis 数组保存的是原点 s 至每个点的当前最短距离
    {                   //因为这个问题,程序一度中止;
        if (dist[i] > max)
        {
            max = dist[i];
        }
    }
    return max;
}

int main()
{
    int ss;
    cin >> vertexNum;
    while (vertexNum != 0)
    {
        edgeNum = 0;
        Index = 0;
        memset(weight, 0, sizeof(weight));
        memset(edgeStack, 0, sizeof(edgeStack));
        minTime = 10000;

        input();
        for (int s=1; s<=vertexNum; s++)
        {
            Bellman_Ford(s);
            int maxTime = SelectMax(dis);
            if (maxTime < minTime)
            {
                minTime = maxTime;
                ss = s;
            }
        }
        if (minTime != MAX)      
        {
            cout << ss << ' ';
            Bellman_Ford(ss);
            cout << minTime << endl;
        }
        else                 //不要忘了检测 disjoint(非连通);
        {
            cout << "disjoint" << endl;
        }
        cin >> vertexNum;
    }
    return 0;
}

  我用数组保存输入的边,以供 Bellman-Ford 算法使用。也可以在 Bellman-Ford 算法中检查 weight 数组的值是否修改,以确定一对节点是否连通,不过这样的话要多一重循环。考虑到时间复杂度,我选择前一种方法。不过,代码多了一倍,也用了更多的时间。总之,各有利弊。在 PushEdge 和 PopEdge 两个函数上的前后置运算符Index++, --index上用了一些时间,一定要记得,如果 PushEdge 中使用 Index++,PopEdge 就一定要用 --index。(久不写代码,生疏了。)

posted @ 2011-08-31 18:00  SunnyDay2015  阅读(211)  评论(0编辑  收藏  举报