一、设计最短路径的动态规划算法
<算法导论>中一般将设计动态规划算法归纳为下面几个步骤:
1)分析最优解的结构
2)递归定义最优解的值
3)自底向上计算最优解的值
4)从计算的最优解的值上面构建出最优解
二、最短路径的结构
从最优解的结构开始分析(我们假设没有权值为负的路径),对于图G<V,E>的所有结点对最短路径的问题,我们能知道一条最短路径的子路径都是最短路径。假设用邻接矩阵W=w(ij)来表示输入带权图,考虑从结点i到结点j的一条最短路径p,如果p最多有m(m为有限值)条边。若i=j,则p的权值为0而且不包含其他边。若i ≠ j,可以将i到j的路径转换为i -> k、k->j。
三、一个给定的图
1)给定一个有向图
2)我们可以给出这个有向图的邻接矩阵
四、C++实现
1 #include <iostream> 2 #include<fstream> 3 #include<sstream> 4 #include<vector> 5 #include<string> 6 using namespace std; 7 const int Max_Num = 100; 8 9 typedef struct Point { 10 int n; //点的个数 11 double p[Max_Num]; 12 double q[Max_Num]; 13 int root[Max_Num][Max_Num]; 14 double w[Max_Num][Max_Num]; 15 double e[Max_Num][Max_Num]; 16 }Point; 17 18 vector<Point> points; 19 vector<string> res; 20 vector<int> num; 21 22 void file_read(); 23 void createPoint(); 24 void optimalBST(); 25 void printRoot(Point P); 26 void printOptimalBST(int i, int j, int r, Point P, ofstream &fileWrite); 27 template <class Type> 28 Type stringToNum(const string& str) { 29 istringstream iss(str); 30 Type num; 31 iss >> num; 32 iss.str(""); 33 return num; 34 } 35 36 void file_read() { 37 string str2, str1 = "", result; 38 ifstream fileRead("in.dat"); 39 if (fileRead.is_open()) { 40 while (getline(fileRead, str2, ' ')) { 41 if (str2.find(" ") != -1) { 42 str1.append(str2 + " "); 43 } 44 else { 45 num.push_back(stringToNum<int>(str2)); 46 if (str1 != "") { 47 res.push_back(str1); 48 } 49 str1 = ""; 50 } 51 } 52 res.push_back(str1); 53 fileRead.close(); 54 } 55 } 56 57 void createPoint() { 58 string temp; 59 Point P; 60 for (int i = 0; i < res.size(); i++) { 61 vector<string> temp_str; //存放按照空格分开后的数字 62 int n = num[i]; 63 stringstream input(res[i]); 64 while (input >> temp) { 65 temp_str.push_back(temp); 66 } 67 P.n = n; 68 for(int k = 0; k<=n; k++) P.p[k] = stringToNum<double>(temp_str[k]); 69 for(int k = n + 1; k<temp_str.size(); k++) P.q[k-(n+1)] = stringToNum<double>(temp_str[k]); 70 points.push_back(P); 71 } 72 } 73 74 //根据书上的伪代码:接收概率列表p1....pn和q0.....qn以及规模n作为输入 计算出e和root 75 void optimalBST(){ 76 Point P; 77 for(int i = 0; i<res.size(); i++) { 78 vector<string> temp_str; //存放按照空格分开后的数字 79 int n = num[i]; 80 string temp; 81 stringstream input(res[i]); 82 while (input >> temp) { 83 temp_str.push_back(temp); 84 } 85 P.n = n; 86 87 for(int k = 0; k<=n; k++) P.p[k] = stringToNum<double>(temp_str[k]); 88 for(int k = n + 1; k<temp_str.size(); k++) P.q[k-(n+1)] = stringToNum<double>(temp_str[k]); 89 90 //初始化只包括虚拟键的子树 91 for (int i = 1;i <= P.n + 1;++i){ 92 P.w[i][i-1] = P.q[i-1]; 93 P.e[i][i-1] = P.q[i-1]; 94 } 95 //由下到上,由左到右逐步计算 96 for (int len = 1;len <= P.n;++len){ 97 for (int i = 1;i <= P.n - len + 1;++i){ 98 int j = i + len - 1; 99 P.e[i][j] = Max_Num; 100 P.w[i][j] = P.w[i][j-1] + P.p[j] + P.q[j]; 101 //求取最小代价的子树的根 102 for (int r = i;r <= j;++r) 103 { 104 double temp = P.e[i][r-1] + P.e[r+1][j] + P.w[i][j]; 105 if (temp < P.e[i][j]) 106 { 107 P.e[i][j] = temp; 108 P.root[i][j] = r; 109 } 110 } 111 } 112 } 113 points.push_back(P); 114 } 115 } 116 117 void printOptimalBST(int i, int j, int r, Point P, ofstream &fileWrite){ 118 int root_node = P.root[i][j];//子树根节点 119 if (root_node == P.root[1][P.n]){ 120 //输出整棵树的根 121 fileWrite << "k" << root_node << "是根" << endl; 122 printOptimalBST(i, root_node - 1, root_node, P, fileWrite); 123 printOptimalBST(root_node +1 , j, root_node, P, fileWrite); 124 return; 125 } 126 127 if (j < i - 1){ 128 return; 129 }else if (j == i - 1){//遇到虚拟键 130 if (j < r) 131 fileWrite << "d" << j << "是" << "k" << r << "的左孩子" << endl; 132 else 133 fileWrite << "d" << j << "是" << "k" << r << "的右孩子" << endl; 134 return; 135 } 136 else{//遇到内部结点 137 if (root_node < r) 138 fileWrite << "k" << root_node << "是" << "k" << r << "的左孩子" << endl; 139 else 140 fileWrite << "k" << root_node << "是" << "k" << r << "的右孩子" << endl; 141 } 142 printOptimalBST(i, root_node - 1, root_node, P, fileWrite); 143 printOptimalBST(root_node + 1, j, root_node, P, fileWrite); 144 } 145 146 //输出最优二叉查找树所有子树的根 147 void printRoot(Point P){ 148 cout << "各子树的根:" << endl; 149 for (int i = 1;i <= P.n;++i){ 150 for (int j = 1;j <= P.n;++j){ 151 cout << P.root[i][j] << " "; 152 } 153 cout << endl; 154 } 155 cout << endl; 156 } 157 158 int main(){ 159 file_read(); 160 optimalBST(); 161 ofstream fileWrite("out.dat"); 162 Point P ; 163 for(int i = 0; i<points.size(); i++) { 164 P = points[i]; 165 printRoot(P); 166 printOptimalBST(1,P.n,-1, P, fileWrite); 167 } 168 fileWrite.clear(); 169 return 0; 170 }
上述代码是将给定的邻接矩阵从文件中读取
然后根据输入的邻接矩阵求出最短路径