????在一个图中,若从一个结点到另一个结点存在着路径,定义路径长度为一条路径上所经过的边的权值之和。从一个结点到令一个结点可能存在着多条路径,路径最短的那条称作最短路径。
??? 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
?
?
?
?