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