动态规划实现最短路径问题

Java基础

浏览数:819

2019-7-25

一、设计最短路径的动态规划算法

  <算法导论>中一般将设计动态规划算法归纳为下面几个步骤:

  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, '\n')) {
 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 }

   上述代码是将给定的邻接矩阵从文件中读取

    

    然后根据输入的邻接矩阵求出最短路径

    

 

作者:风沙迷了眼