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。(久不写代码,生疏了。)

你可能感兴趣的:(broker)