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