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

浙公网安备 33010602011771号