在一个图中,若从一个结点到另一个结点存在着路径,定义路径长度为一条路径上所经过的边的权值之和。从一个结点到令一个结点可能存在着多条路径,路径最短的那条称作最短路径。
Dijkastra思想(不能包含负权值的边):
设置两个结点集合S和T,S中存放已找到最短路径的结点,T中存放当前还未找到最短路径的结点。初始状态S中只包含起始点u0。然后不断的从集合T中选择到u0路径长度最短的结点v,每次加入,都要修改从源点u0到集合T中剩余结点的当前最短路径长度,为原来路径长度与u0经过v到达该结点的路径长度中的较小者。当T为空,算法结束。
Dijkastra设计:
distance数组用来记录从源点到其余个点的当前最短距离数值。
#include <iostream>
using namespace std;
const int MAX = 200000000;
int n; //物品总数
int m; //等级差距*
int graph[101][101]; //图
int d[101]; //从开始点到其余个点的花费
int value[101]; //物品本身的价值*
int level[101]; //物品等级*
bool s[101],in_limit[101]; //标记数组*
int dijkastra()
{
int result = MAX;
int i,j;
int k,dis;
memset(s,0,sizeof(s));
for(i = 2,d[1] = 0; i <= n; i++)
d[i] = MAX;
for(i = 1; i <= n; i++)
{
k = 0;
dis = MAX;
for(j = 1; j <= n; j++)
if(!s[j] && d[j] <= dis && in_limit[j])
{
k = j;
dis = d[j];
}
s[k] = 1;
for(j = 1; j <= n; j++)
{
if(in_limit[j] && d[j] > d[k] + graph[k][j])
d[j] = d[k] + graph[k][j];
}
}
for(i = 1; i <= n; i++)
{
d[i] += value[i];
if(d[i] < result)
result = d[i];
}
return result;
}
int main()
{
int i,j;
int result = MAX,t = 0;
int t1,v1;
int x;
cin>>m>>n;
for(i=0;i<=n;i++)
for(j=0;j<=n;j++)
if(i == j)
graph[i][j] = 0;
else
graph[i][j] = MAX;
for(i = 1; i <= n; i++)
{
cin>>value[i]>>level[i]>>x;
for(j = 1; j <= x; j++)
{
cin>>t1>>v1;
graph[i][t1] = v1;
}
}
for(i = 0; i <= m; i++)
{
memset(in_limit,0,sizeof(in_limit));
for(j = 1; j <= n; j++)
if(level[j] >= level[1]-m+i && level[j] <= level[1]+i)
in_limit[j] = 1;
t = dijkastra();
if(result > t)
result = t;
}
cout<<result<<endl;
return 0;
}
上述迪杰斯特拉算法可以求出某个结点与其他结点的最短路径,现在考虑这样一个问题:求出图中每对顶点的最短路径。用简单的方法,把每个顶点作为源点,用迪杰斯特拉,可以求出每对结点的最短路径。其实还有更简单的方法——弗洛伊德算法。(代码简单,思维复杂)
folyd思想(动归,可以包含负权值的边,但不能有负环):
将图G中顶点编号,从1到n。现在考虑从i到j的最短路径,若k是这条路上的中间结点,那么由i到k和由k到j的这两条子路径应分别是由i到k和由k到j的最短路径。否则,这条由i到j的路径就不是具有最小长度的路径。于是,最优性原理成立,这表明有使用动态规划的可能性。如果k是编号最高的中间结点,那么由i到k的这条路径上就不会有比k-1更大的结点通过。同样,由k到j路径上也不会有比k-1更大的结点通过。因此,可以把求取一条由i到j的最短路径看成如下过程:首先需要决策哪一个结点是该路径上具有最大编号的中间结点k,然后就再去求由i到k和由k到j这两对结点间的最短路径。当然,这两条路径都不可能有比k-1还大的中间结点。
则得到递推式:
A(i,j)k = min{A(i,j)k-1 , A(i,k)k-1 + A(k,j)k-1)}, k>=1
import java.io.BufferedInputStream;
import java.util.Scanner;
public class Main {
public static int MAX = 991;
public static int[][] map = new int[101][101];
public static int n;
public static void floyd() {
int i, j, k;
for (k = 1; k <= n; k++) {
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++) {
if (i != k && j != k) {
if (map[i][k] + map[k][j] < map[i][j])
map[i][j] = map[i][k] + map[k][j];
}
}
}
}
}
public static void initial() {
int i, j;
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
map[i][j] = MAX;
}
public static void main(String[] args) {
int i,j,t,a;
int result1,result2;
boolean flag = false;
Scanner cin = new Scanner(new BufferedInputStream(System.in));
while((n = cin.nextInt()) != 0) {
result1 = 0;
result2 = MAX;
initial();
for(i = 1;i <= n; i++) {
t = cin.nextInt();
for (j = 1; j <= t; j++) {
a = cin.nextInt();
map[i][a] = cin.nextInt();
}
}
floyd();
flag = false;
for (i = 1; i <= n; i++) {
t = 0;
for (j = 1; j <= n; j++) {
if (i != j) {
if (map[i][j] == MAX) {
t = 0;
break;
}
if (map[i][j] > t)
t = map[i][j];
}
}
if (t != 0) {
flag = true;
if (t < result2) {
result1 = i;
result2 = t;
}
}
}
if(!flag)
System.out.println("disjoint");
else
System.out.println(result1 + " " +result2);
}
}
}
参见poj1062,1125