题目
Problem Description
给出一个有向图G=(V,E)和一个源点v0属于V,请写一个程序输出v0和图中其他顶点的最短路径。只要所有的有向环权值都是正的,我们就允许图的边有负值。顶点的标号1到n(n为图G的顶点数)。
输入有多组数据,每组数据第1行:一个正数n(2<=n<=80),表示图G的顶点总数。
第2行:一个整数,表示源点v0(v0属于V,v0可以是图G中任意一个顶点)。
第3至第n+2行,用一个邻接矩阵W给出了这个图。
Output
对于每组输入输出共包含n-1行,按照顶点编号从小到大的顺序,每行输出源点v0到一个顶点的最短距离。每行的具体格式参照样例。
5
1
0 2 - - 10
- 0 3 - 7
- - 0 4 -
- - - 0 5
- - 6 - 0
Sample Output
(1 -> 2) = 2
(1 -> 3) = 5
(1 -> 4) = 9
(1 -> 5) = 9
解题思路
简单的图论最短路径问题,用 Bellman-Ford 算法的队列优化(也就是所谓的 SPFA 算法)解决,同时使用 SLF 策略进行优化。
解题代码
//
// main.cpp
// 最短路径
//
// Created by Yeah on 14-7-22.
// Copyright (c) 2014年 Yeah. All rights reserved.
//
#include <iostream>
#include <deque>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
const int MAXN = 5000;
const long long INF = 50000000000000;
struct Edge
{
int To;
long long Weight;
};
/**
* @brief 对输入的每一行进行处理,数据存入邻接矩阵
*
* @param k 当前处理的顶点编号
* @param str 顶点编号对应的那一行输入数据
* @param Matrix 邻接矩阵,其中 Matrix[i][0] 可认为是一个指示器
*/
void Make_Matrix(int NodeNo, string str, long long Matrix[MAXN][MAXN])
{
//string::size_type len = str.size();
bool flag(false);
long long tmp(0);
for(string::iterator it(str.begin()); it != str.end(); ++it)
{
if ((*it == '-' && it == str.end() - 1) || (*it == '-' && *(it + 1) == ' '))
{
tmp = INF;
continue;
}
if(isalnum(*it))
{
tmp = tmp * 10 + *it - '0';
}
else if(*it == '-' && isalnum(*(it + 1)))
flag = 1;
if(*it == ' ')
{
if(!flag)
Matrix[NodeNo][++Matrix[NodeNo][0]] = tmp;
if(flag)
Matrix[NodeNo][++Matrix[NodeNo][0]] = tmp * -1;
flag = false;
tmp = 0;
}
}
}
/**
* @brief SPFA 算法求源点到最短路径,处理结果保存在 Distance 数组里
* @param Source 源点编号(从 1 开始)
* @param NodeSum 图中顶点数
* @param in_Queue 数组,in_Queue[i] 标记编号为 i 的顶点是否在队列里面
* @param in_Cnt 数组,in_Cnt[i] 记录编号为 i 的顶点进入队列的总次数
* @param Distance 数组,Distance[i] 记录编号为 i 的顶点到源点的最短距离
* @param Adjacency_Map 数组,代表邻接表,vector::size() 为邻接顶点个数
* @return true 不存在负权环
* @return false 存在负权环
* @see http://www.nocow.cn/index.php/SPFA%E7%AE%97%E6%B3%95
*/
bool SPFA(int Source, int NodeSum, bool in_Queue[], int in_Cnt[], long long Distance[], vector<Edge> Adjacency_Map[])
{
deque<int> DQ; // Double-ended Queue,双端队列,用于 SLF 优化策略
// 初始化
for (int i(1); i <= NodeSum; i++)
{
in_Queue[i] = false;
in_Cnt[i] = 0;
Distance[i] = INF;
}
// 源点进队列
DQ.push_back(Source);
in_Queue[Source] = true;
in_Cnt[Source]++;
Distance[Source] = 0;
while (!DQ.empty())
{
// 顶点出队列
int Now = DQ.front();
in_Queue[Now] = false;
DQ.pop_front();
int To(0);
for (int i(0); i < Adjacency_Map[Now].size(); i++)
{
To = Adjacency_Map[Now][i].To;
if ((Distance[Now] < INF) && (Distance[To] > Distance[Now] + Adjacency_Map[Now][i].Weight))
{
// 松弛操作
Distance[To] = Distance[Now] + Adjacency_Map[Now][i].Weight;
if (!in_Queue[To])
{
in_Queue[To] = true;
in_Cnt[To]++;
if (in_Cnt[To] == NodeSum)
return false; // 顶点入队总次数超过顶点个数,说明存在负权环
if (!DQ.empty())
{
// 这里使用了 SLF (Small Label First) 策略来对算法进行优化
if(Distance[To] > Distance[DQ.front()])
DQ.push_back(To);
else
DQ.push_front(To);
}
else
DQ.push_back(To);
}
}
}
}
return true;
}
long long Matrix[MAXN][MAXN]; // 邻接矩阵
long long Distance[MAXN]; // 源点到各点的最短路径
vector<Edge> Adjacency_Map[MAXN]; // 邻接表
bool in_Queue[MAXN]; // 顶点是否在队列中
int in_Cnt[MAXN]; // 顶点入队次数
int main()
{
Edge temp;
int NodeSum; //顶点数
while (cin >> NodeSum)
{
int Source;
cin >> Source;
cin.ignore();
for (int i = 1; i <= NodeSum; i++)
{
Adjacency_Map[i].clear(); //清空邻接表
Matrix[i][0] = 0; //清空邻接矩阵指示器
}
string str;
for (int i(1); i <= NodeSum; ++i)
{
getline(cin, str);
str += ' ';
Make_Matrix(i, str, Matrix);
}
for (int From(1); From <= NodeSum; From++)
{
for (int To(1); To <= NodeSum; ++To)
{
if (From != To)
{
temp.To = To;
temp.Weight = Matrix[From][To];
Adjacency_Map[From].push_back(temp);
}
}
}
SPFA(Source, NodeSum, in_Queue, in_Cnt, Distance, Adjacency_Map);
for (int i(1); i <= NodeSum; ++i)
{
if (i == Source)
{
continue;
}
cout << '(' << Source << " -> " << i << ") = " << Distance[i] << endl;
}
}
return 0;
}
题目链接
:暂无