《趣學演算法》第四章 動態規劃原始碼
阿新 • • 發佈:2020-09-02
動態規劃相關程式碼實現:
目錄
1、孩子有多像爸爸——最長的公共子序列
//program 4-1 #include <iostream> #include<cstring> using namespace std; const int N=1002; int c[N][N],b[N][N]; char s1[N],s2[N]; int len1,len2; void LCSL() { int i,j; for(i = 1;i <= len1;i++)//控制s1序列不同的子問題 for(j = 1;j <= len2;j++)//控制s2序列不同的子問題 { if(s1[i-1]==s2[j-1]) { c[i][j] = c[i-1][j-1]+1;//如果當前字元相同,則公共子序列的長度為該字元前的最長公共序列+1 b[i][j] = 1; } else { if(c[i][j-1]>=c[i-1][j]) { c[i][j] = c[i][j-1]; b[i][j] = 2; } else { c[i][j] = c[i-1][j]; b[i][j] = 3; } } } } void print(int i, int j)//根據記錄下來的資訊構造最長公共子序列(從b[i][j]開始遞推) { if(i==0 || j==0) return; if(b[i][j]==1) { print(i-1,j-1); cout<<s1[i-1]; } else if(b[i][j]==2) print(i,j-1); else print(i-1,j); } int main() { int i,j; cout << "輸入字串s1:"<<endl; cin >> s1; cout << "輸入字串s2:"<<endl; cin >> s2; len1 = strlen(s1);//計算兩個字串的長度 len2 = strlen(s2); for(i = 0;i <= len1;i++) { c[i][0]=0;//初始化第一列為0 } for(j = 0;j<= len2;j++) { c[0][j]=0;//初始化第一行為0 } LCSL(); cout << "s1和s2的最長公共子序列長度是:"<<c[len1][len2]<<endl; cout << "s1和s2的最長公共子序列是:"; print(len1,len2); cout<<endl; // /*用於測試 cout<<"c[i][j]陣列:"<<endl; for(i = 0;i <= len1;i++) { for(j = 0;j <= len2;j++) cout <<" "<<c[i][j]; cout<<endl; } cout<<"b[i][j]陣列:"<<endl; for(i = 0;i <= len1;i++) { for(j = 0;j <= len2;j++) cout <<" "<<b[i][j]; cout<<endl; } // */用於測試 return 0; }
2、DNA基因鑑定——編輯距離
//program 4-2 #include <iostream> #include <cstring> using namespace std; const int N=100; char str1[N],str2[N]; int d[N][N]; //定義輔助陣列,d[i][j]表示str1前i個字元和str2前j個字元的編輯距離。 int min(int a, int b) { return a<b?a:b;//返回較小的值 } int editdistance(char *str1, char *str2) { int len1 = strlen(str1); int len2 = strlen(str2);//取字串大小 for(int i=0;i<=len1;i++)//當第二個串長度為0,編輯距離初始化為i d[i][0]= i; for(int j=0;j<=len2;j++)//當第一個串長度為0,編輯距離初始化為j d[0][j]=j; for(int i=1;i <=len1;i++)//遍歷兩個陣列 { for(int j=1;j<=len2;j++) { int diff;//判斷str[i]是否等於str2[j],相等為0,代表不用改變str1,不相等為1,代表需要改變str1。 if(str1[i-1] == str2[j-1])//相等 diff = 0 ; else diff = 1 ; int temp = min(d[i-1][j] + 1, d[i][j-1] + 1);//先兩者取最小值 d[i][j] = min(temp, d[i-1][j-1] + diff);//再取最小值,相當於三者取最小值d[i-1][j] + 1, d[i][j-1] + 1,d[i-1][j-1] + diff } } return d[len1][len2]; } int main() { cout << "輸入字串str1:"<<endl; cin >> str1; cout << "輸入字串str2:"<<endl; cin >> str2; cout << str1<< "和"<<str2<<"的編輯距離是:"<<editdistance(str1,str2); return 0; }
3、長江一日遊——遊艇租賃
//program 4-3 #include<iostream> using namespace std; const int ms = 1000; int r[ms][ms],m[ms][ms],s[ms][ms]; //i到j站的租金 int n; //共有n個站點 void rent() { int i,j,k,d; for(d=3;d<=n;d++) //將問題分為小規模為d { for(i=1;i<=n-d+1;i++) { j=i+d-1; for(k=i+1;k<j;k++) //記錄每一個小規模內的最優解 { int temp; temp=m[i][k]+m[k][j]; if(temp<m[i][j]) { m[i][j]=temp; s[i][j]=k; } } } } } void print(int i,int j) { if(s[i][j]==0 ) { cout << "--"<<j; return ; } print(i,s[i][j]); print(s[i][j],j); } int main() { int i,j; cout << "請輸入站點的個數 n:"; cin >> n; cout << "請依次輸入各站點之間的租金:"; for(i=1;i<=n;i++) for(j=i+1;j<=n;++j) { cin>>r[i][j]; m[i][j]=r[i][j]; } rent(); cout << "花費的最少租金為:" <<m[1][n] << endl; cout <<"最少租金經過的站點:"<<1; print(1,n); // /*用於測試 輸出m[][]和s[][]陣列 cout << endl; for (i = 1; i <= n; i++ ) { for (j = 1; j <=2*(i-1); j++ ) cout << " " ; for (j=i; j<=n;j++ ) cout << m[i][j]<<" " ; cout << endl; } for (i=1; i<=n;i++ ) { for (j =1; j <=2*(i-1);j++ ) cout << " " ; for (j=i; j<=n; j++ ) cout << s[i][j]<<" " ; cout << endl; } cout << endl; // /*/用於測試 return 0; }
4、快速計算——矩陣連乘
//program 4-4
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int msize = 100;
int p[msize];
int m[msize][msize];
int s[msize][msize];
int n;
void matrixchain()
{
int i,j,r,k;
memset(m,0,sizeof(m));
memset(s,0,sizeof(s));
for(r = 2; r <= n; r++) //不同規模的子問題
{
for(i = 1; i <= n-r+1; i++)
{
j = i + r - 1;
m[i][j] = m[i+1][j] + p[i-1] * p[i] * p[j]; //決策為k=i的乘法次數
s[i][j] = i; //子問題的最優策略是i;
for(k = i+1; k < j; k++) //對從i到j的所有決策,求最優值,記錄最優策略
{
int t = m[i][k] + m[k+1][j] + p[i-1] * p[k] * p[j];
if(t < m[i][j])
{
m[i][j] = t;
s[i][j] = k;
}
}
}
}
}
void print(int i,int j)
{
if( i == j )
{
cout <<"A[" << i << "]";
return ;
}
cout << "(";
print(i,s[i][j]);
print(s[i][j]+1,j);
cout << ")";
}
int main()
{
cout << "請輸入矩陣的個數 n:";
cin >> n;
int i ,j;
cout << "請依次輸入每個矩陣的行數和最後一個矩陣的列數:";
for (i = 0; i <= n; i++ )
cin >> p[i];
matrixchain();
print(1,n);
cout << endl;
/*用於測試
for (i = 1; i <= n; i++ )
{
for (j = i; j <= n; j++ )
cout << m[i][j]<<" " ;
cout << endl;
}
for (i = 1; i <= n; i++ )
{
for (j = i; j <= n; j++ )
cout << s[i][j]<<" " ;
cout << endl;
}
cout << endl;
*/
cout << "最小計算量的值為 " << m[1][n] << endl;
}
5、切呀切皮薩——最優三角剖分
//program 4-5
#include<iostream>
#include<sstream>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std ;
const int M= 1000 + 5 ;
int n ;
int s[M][M] ;
double m[M][M],g[M][M];
void Convexpolygontriangulation()
{
for(int i = 1 ;i <= n ; i++) // 初始化
{
m[i][i] = 0 ;
s[i][i] = 0 ;
}
for(int d = 2 ;d <= n ; d++) // 列舉點的個數
for(int i = 1 ;i <= n - d + 1 ; i++) // 列舉起始點
{
int j = i + d - 1 ; // 終點
m[i][j] = m[i+1][j] + g[i-1][i] + g[i][j] + g[i-1][j] ;
s[i][j] = i ;
for(int k = i + 1 ;k < j ; k++) // 列舉中間點
{
double temp = m[i][k] + m[k+1][j] + g[i-1][k] + g[k][j] + g[i-1][j] ;
if(m[i][j] > temp)
{
m[i][j] = temp ; // 更新最優值
s[i][j] = k ; // 記錄中間點
}
}
}
}
void print(int i , int j) // 輸出所有的弦
{
if(i == j) return ;
if(s[i][j]>i)
cout<<"{v"<<i-1<<"v"<<s[i][j]<<"}"<<endl;
if(j>s[i][j]+1)
cout<<"{v"<<s[i][j]<<"v"<<j<<"}"<<endl;
print(i ,s[i][j]);
print(s[i][j]+1 ,j);
//cout<<"{ v"<<i-1<<" , v"<<s[i][j]<<" , v"<<j<<" }"<<endl; //輸出所有剖分後的三角形
}
int main()
{
int i,j;
cout << "請輸入頂點的個數 n:";
cin >> n;
n-- ;
cout << "請依次輸入各頂點的連線權值:";
for(int i = 0 ;i <= n ; i++) // 輸入各個頂點之間的距離
for(int j = 0 ;j <= n ; j++)
cin>>g[i][j] ;
Convexpolygontriangulation();
cout<<m[1][n]<<endl;
// /*用於測試 輸出m[][]和s[][]陣列
for (i = 1; i <= n; i++ )
{
for (j = 1; j <=2*(i-1); j++ )
cout << " " ;
for (j = i; j <= n; j++ )
cout << m[i][j]<<" " ;
cout << endl;
}
for (i = 1; i <= n; i++ )
{
for (j = 1; j <=2*(i-1); j++ )
cout << " " ;
for (j = i; j <= n; j++ )
cout << s[i][j]<<" " ;
cout << endl;
}
cout << endl;
// /*/用於測試
print(1 ,n); // 列印路徑
return 0 ;
}
6、小石子游戲——石子合併
//program 4-6
#include <iostream>
#include <string>
using namespace std;
const int INF = 1 << 30;
const int N = 205;
int Min[N][N], Max[N][N];
int sum[N];
int a[N];
int min_Circular,max_Circular;
void straight(int a[],int n)
{
for(int i=1;i<=n;i++) // 初始化
Min[i][i]=0, Max[i][i]=0;
sum[0]=0;
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+a[i];
for(int v=2; v<=n; v++) // 列舉合併的堆數規模
{
for(int i=1; i<=n-v+1; i++) //列舉起始點i
{
int j = i + v-1; //列舉終點j
Min[i][j] = INF; //初始化為最大值
Max[i][j] = -1; //初始化為-1
int tmp = sum[j]-sum[i-1];//記錄i...j之間的石子數之和
for(int k=i; k<j; k++) { //列舉中間分隔點
Min[i][j] = min(Min[i][j], Min[i][k] + Min[k+1][j] + tmp);
Max[i][j] = max(Max[i][j], Max[i][k] + Max[k+1][j] + tmp);
}
}
}
}
void Circular(int a[],int n)
{
for(int i=1;i<=n-1;i++)
a[n+i]=a[i];
n=2*n-1;
straight(a, n);
n=(n+1)/2;
min_Circular=Min[1][n];
max_Circular=Max[1][n];
for(int i=2;i<=n;i++)
{
if(Min[i][n+i-1]<min_Circular)
min_Circular=Min[i][n+i-1];
if(Max[i][n+i-1]>max_Circular)
max_Circular=Max[i][n+i-1];
}
}
int main()
{
int n;
cout << "請輸入石子的堆數 n:";
cin >> n;
cout << "請依次輸入各堆的石子數:";
for(int i=1;i<=n;i++)
cin>>a[i];
straight(a, n);
cout<<"路邊玩法(直線型)最小花費為:"<<Min[1][n]<<endl;
cout<<"路邊玩法(直線型)最大花費為:"<<Max[1][n]<<endl;
Circular(a,n);
cout<<"操場玩法(圓型)最小花費為:"<<min_Circular<<endl;
cout<<"操場玩法(圓型)最大花費為:"<<max_Circular<<endl;
return 0;
}
//program 4-6-1
#include <iostream>
#include <string>
using namespace std;
const int INF = 1 << 30;
const int N = 205;
int Min[N][N], Max[N][N],s[N][N];
int sum[N];
int a[N];
int min_Circular,max_Circular;
void get_Min(int n)
{
for(int v=2; v<=n; v++) // 列舉合併的堆數規模
{
for(int i=1; i<=n-v+1; i++) //列舉起始點i
{
int j = i + v-1; //列舉終點j
int tmp = sum[j]-sum[i-1];//記錄i...j之間的石子數之和
int i1=s[i][j-1]>i?s[i][j-1]:i;
int j1=s[i+1][j]<j?s[i+1][j]:j;
Min[i][j]=Min[i][i1]+Min[i1+1][j];
s[i][j]=i1;
for(int k=i1+1; k<=j1; k++) //列舉中間分隔點
if(Min[i][k]+ Min[k+1][j]<Min[i][j])
{
Min[i][j]=Min[i][k]+Min[k+1][j];
s[i][j]=k;
}
Min[i][j]+=tmp;
}
}
}
void get_Max(int n)
{
for(int v=2; v<=n; v++) // 列舉合併的堆數規模
{
for(int i=1; i<=n-v+1; i++) //列舉起始點i
{
int j = i + v-1; //列舉終點j
Max[i][j] = -1; //初始化為-1
int tmp = sum[j]-sum[i-1];//記錄i...j之間的石子數之和
if(Max[i+1][j]>Max[i][j-1])
Max[i][j]=Max[i+1][j]+tmp;
else
Max[i][j]=Max[i][j-1]+tmp;
}
}
}
void straight(int a[],int n)
{
for(int i=1;i<=n;i++) // 初始化
Min[i][i]=0, Max[i][i]=0, s[i][i]=0;
sum[0]=0;
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+a[i];
get_Min(n);
get_Max(n);
}
void Circular(int a[],int n)
{
for(int i=1;i<=n-1;i++)
a[n+i]=a[i];
n=2*n-1;
straight(a, n);
n=(n+1)/2;
min_Circular=Min[1][n];
max_Circular=Max[1][n];
for(int i=2;i<=n;i++)
{
if(Min[i][n+i-1]<min_Circular)
min_Circular=Min[i][n+i-1];
if(Max[i][n+i-1]>max_Circular)
max_Circular=Max[i][n+i-1];
}
}
int main()
{
int n;
cout << "請輸入石子的堆數 n:";
cin >> n;
cout << "請依次輸入各堆的石子數:";
for(int i=1;i<=n;i++)
cin>>a[i];
straight(a, n);
cout<<"路邊玩法(直線型)最小花費為:"<<Min[1][n]<<endl;
cout<<"路邊玩法(直線型)最大花費為:"<<Max[1][n]<<endl;
Circular(a,n);
cout<<"操場玩法(圓型)最小花費為:"<<min_Circular<<endl;
cout<<"操場玩法(圓型)最大花費為:"<<max_Circular<<endl;
return 0;
}
7、大賣場購物車1——0-1揹包問題
//program 4-7
#include <iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 10005
#define M 105
int c[M][maxn];//c[i][j] 表示前i個物品放入容量為j購物車獲得的最大價值
int w[M],v[M];//w[i] 表示第i個物品的重量,v[i] 表示第i個物品的價值
int x[M]; //x[i]表示第i個物品是否放入購物車
int main(){
int i,j,n,W;//n表示n個物品,W表示購物車的容量
cout << "請輸入物品的個數 n:";
cin >> n;
cout << "請輸入購物車的容量W:";
cin >> W;
cout << "請依次輸入每個物品的重量w和價值v,用空格分開:";
for(i=1;i<=n;i++)
cin>>w[i]>>v[i];
for(i=1;i<=n;i++)//初始化第0列為0
c[i][0]=0;
for(j=1;j<=W;j++)//初始化第0行為0
c[0][j]=0;
for(i=1;i<= n;i++)//計算c[i][j]
for(j=1;j<=W;j++)
if(j<w[i]) //當物品的重量大於購物車的容量,則不放此物品
c[i][j] = c[i-1][j];
else //否則比較此物品放與不放是否能使得購物車內的價值最大
c[i][j] = max(c[i-1][j],c[i-1][j-w[i]] + v[i]);
cout<<"裝入購物車的最大價值為:"<<c[n][W]<<endl;
//用於測試
for (i=1; i<=n; i++ )
{
for (j=1; j<=W; j++ )
cout << c[i][j]<<"\t" ;
cout << endl;
}
cout << endl;
//逆向構造最優解
j=W;
for(i=n;i>0;i--)
if(c[i][j]>c[i-1][j])
{
x[i]=1;
j-=w[i];
}
else
x[i]=0;
cout<<"裝入購物車的物品序號為:";
for(i=1;i<=n;i++)
if(x[i]==1)
cout<<i<<" ";
return 0;
}
//program 4-7
#include <iostream>
#include<cstring>
using namespace std;
#define maxn 10005
#define M 105
int dp[maxn];//dp[j] 表示當前已放入容量為j的購物車獲得的最大價值
int w[M],v[M];//w[i] 表示第i個物品的重量,v[i] 表示第i個物品的價值
int x[M]; //x[i]表示第i個物品是否放入購物車
int i,j,n,W;//n表示n個物品,W表示購物車的容量
void opt1(int n,int W)
{
for(i=1;i<=n;i++)
for(j=W;j>0;j--)
if(j>=w[i]) //當物品的重量大於購物車的容量,比較此物品放與不放是否能使得購物車內的價值最大
dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
}
void opt2(int n,int W)
{
for(i=1;i<= n;i++)
for(j=W;j>=w[i];j--)
//當物品的重量大於購物車的容量,比較此物品放與不放是否能使得購物車內的價值最大
dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
}
void opt3(int n,int W)
{
int sum[n];//sum[i]表示從1...i的物品重量之和
sum[0]=0;
for(i=1;i<=n;i++)
sum[i]=sum[i-1]+w[i];
for(i=1;i<=n;i++)
{
int bound=max(w[i],W-(sum[n]-sum[i-1]));//w[i]與剩餘容量取最大值,sum[n]-sum[i-1]表示從i...n的物品重量之和
for(j=W;j>=bound;j--)
//當物品的重量大於購物車的容量,比較此物品放與不放是否能使得購物車內的價值最大
dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
}
}
int main()
{
cout << "請輸入物品的個數 n:";
cin >> n;
cout << "請輸入購物車的容量W:";
cin >> W;
cout << "請依次輸入每個物品的重量w和價值v,用空格分開:";
for(i=1;i<=n;i++)
cin>>w[i]>>v[i];
for(j=1;j<=W;j++)//初始化第0行為0
dp[j]=0;
opt1(n,W);
//opt2(n,W);
//opt3(n,W);
cout<<"裝入購物車的最大價值為:"<<dp[W]<<endl;
//測試dp[]陣列結果
for(j=1;j<=W;j++)
cout<<dp[j]<<" ";
cout<<endl;
/* //逆向構造最優解,無法構造最優解
j=W;
for(i=n;i>0;i--)
{
while(dp[j]==dp[j-1])
j--;
if(dp[j]<=(dp[j-w[i]]+v[i]))
{
x[i]=1;
j-=w[i];
}
else
x[i]=0;
}
cout<<"裝入購物車的物品為:";
for(i=1;i<=n;i++)
if(x[i]==1)
cout<<i<<" ";
*/
return 0;
}
8、快速定位——最優二叉搜尋樹
//program 4-8
#include<iostream>
#include<cmath> //求絕對值函式需要引入該標頭檔案
using namespace std;
const int M=1000+5;
double c[M][M],w[M][M],p[M],q[M];
int s[M][M];
int n,i,j,k;
void Optimal_BST()
{
for(i=1;i<=n+1;i++)
{
c[i][i-1]=0.0;
w[i][i-1]=q[i-1];
}
for(int t=1;t<=n;t++)//t為關鍵字的規模
//從下標為i開始的關鍵字到下標為j的關鍵字
for(i=1;i<=n-t+1;i++)
{
j=i+t-1;
w[i][j]=w[i][j-1]+p[j]+q[j];
c[i][j]=c[i][i-1]+c[i+1][j];//初始化
s[i][j]=i;//初始化
//選取i+1到j之間的某個下標的關鍵字作為從i到j的根,如果組成的樹的期望值當前最小,則k為從i到j的根節點
for(k=i+1;k<=j;k++)
{
double temp=c[i][k-1]+c[k+1][j];
if(temp<c[i][j]&&fabs(temp-c[i][j])>1E-6)//C++中浮點數因為精度問題不可以直接比較
{
c[i][j]=temp;
s[i][j]=k;//k即為從下標i到j的根節點
}
}
c[i][j]+=w[i][j];
}
}
void Construct_Optimal_BST(int i,int j,bool flag)
{
if(flag==0)
{
cout<<"S"<<s[i][j]<<" 是根"<<endl;
flag=1;
}
int k=s[i][j];
//如果左子樹是葉子
if(k-1<i)
{
cout<<"e"<<k-1<<" is the left child of "<<"S"<<k<<endl;
}
//如果左子樹不是葉子
else
{
cout<<"S"<<s[i][k-1]<<" is the left child of "<<"S"<<k<<endl;
Construct_Optimal_BST(i,k-1,1);
}
//如果右子樹是葉子
if(k>=j)
{
cout<<"e"<<j<<" is the right child of "<<"S"<<k<<endl;
}
//如果右子樹不是葉子
else
{
cout<<"S"<<s[k+1][j]<<" is the right child of "<<"S"<<k<<endl;
Construct_Optimal_BST(k+1,j,1);
}
}
int main()
{
cout << "請輸入關鍵字的個數 n:";
cin >> n;
cout<<"請依次輸入每個關鍵字的搜尋概率:";
for (i=1; i<=n; i++ )
cin>>p[i];
cout << "請依次輸入每個虛結點的搜尋概率:";
for (i=0; i<=n; i++)
cin>>q[i];
Optimal_BST();
// /*用於測試
for(i=1; i<=n+1;i++)
{
for (j=1; j<i;j++)
cout <<"\t" ;
for(j=i-1;j<=n;j++)
cout << w[i][j]<<"\t" ;
cout << endl;
}
for(i=1; i<=n+1;i++)
{
for (j=1; j<i;j++)
cout <<"\t" ;
for(j=i-1; j<=n;j++)
cout << c[i][j]<<"\t" ;
cout << endl;
}
for(i=1; i<=n;i++)
{
for (j=1; j<i;j++)
cout << "\t" ;
for(j=i-1; j<=n;j++)
cout << s[i][j]<<"\t" ;
cout << endl;
}
cout << endl;
// */用於測試
cout<<"最小的搜尋成本為:"<<c[1][n]<<endl;
cout<<"最優二叉搜尋樹為:";
Construct_Optimal_BST(1,n,0);
return 0;
}
//program 4-8-1
#include<iostream>
#include<cmath> //求絕對值函式需要引入該標頭檔案
using namespace std;
const int M=1000+5;
double c[M][M],w[M][M],p[M],q[M];
int s[M][M];
int n,i,j,k;
void Optimal_BST()
{
for(i=1;i<=n+1;i++)
{
c[i][i-1]=0.0;
w[i][i-1]=q[i-1];
}
for(int t=1;t<=n;t++)//t為關鍵字的規模
//從下標為i開始的關鍵字到下標為j的關鍵字
for(i=1;i<=n-t+1;i++)
{
j=i+t-1;
w[i][j]=w[i][j-1]+p[j]+q[j];
int i1=s[i][j-1]>i?s[i][j-1]:i;
int j1=s[i+1][j]<j?s[i+1][j]:j;
c[i][j]=c[i][i1-1]+c[i1+1][j];//初始化
s[i][j]=i1;//初始化
//選取i1+1到j1之間的某個下標的關鍵字作為從i到j的根,如果組成的樹的期望值當前最小,則k為從i到j的根節點
for(k=i1+1;k<=j1;k++)
{
double temp=c[i][k-1]+c[k+1][j];
if(temp<c[i][j]&&fabs(temp-c[i][j])>1E-6)//C++中浮點數因為精度問題不可以直接比較
{
c[i][j]=temp;
s[i][j]=k;//k即為從下標i到j的根節點
}
}
c[i][j]+=w[i][j];
}
}
void Construct_Optimal_BST(int i,int j,bool flag)
{
if(flag==0)
{
cout<<"S"<<s[i][j]<<" 是根"<<endl;
flag=1;
}
int k=s[i][j];
//如果左子樹是葉子
if(k-1<i)
{
cout<<"e"<<k-1<<" is the left child of "<<"S"<<k<<endl;
}
//如果左子樹不是葉子
else
{
cout<<"S"<<s[i][k-1]<<" is the left child of "<<"S"<<k<<endl;
Construct_Optimal_BST(i,k-1,1);
}
//如果右子樹是葉子
if(k>=j)
{
cout<<"e"<<j<<" is the right child of "<<"S"<<k<<endl;
}
//如果右子樹不是葉子
else
{
cout<<"S"<<s[k+1][j]<<" is the right child of "<<"S"<<k<<endl;
Construct_Optimal_BST(k+1,j,1);
}
}
int main()
{
cout << "請輸入關鍵字的個數 n:";
cin >> n;
cout<<"請依次輸入每個關鍵字的搜尋概率:";
for (i=1; i<=n; i++ )
cin>>p[i];
cout << "請依次輸入每個虛結點的搜尋概率:";
for (i=0; i<=n; i++)
cin>>q[i];
Optimal_BST();
// /*用於測試
for(i=1; i<=n+1;i++)
{
for (j=1; j<i;j++)
cout <<"\t" ;
for(j=i-1;j<=n;j++)
cout << w[i][j]<<"\t" ;
cout << endl;
}
for(i=1; i<=n+1;i++)
{
for (j=1; j<i;j++)
cout <<"\t" ;
for(j=i-1; j<=n;j++)
cout << c[i][j]<<"\t" ;
cout << endl;
}
for(i=1; i<=n;i++)
{
for (j=1; j<i;j++)
cout << "\t" ;
for(j=i-1; j<=n;j++)
cout << s[i][j]<<"\t" ;
cout << endl;
}
cout << endl;
// */用於測試
cout<<"最小的搜尋成本為:"<<c[1][n]<<endl;
cout<<"最優二叉搜尋樹為:";
Construct_Optimal_BST(1,n,0);
return 0;
}