生活随笔
收集整理的這篇文章主要介紹了
C++——《算法分析》实验叁——贪心算法与回溯法
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
實(shí)驗(yàn)?zāi)康?#xff1a;
1、理解貪心算法與回溯法的概念;
2、掌握貪心算法與回溯法的基本要素;
3、掌握貪心算法與回溯法的解題步驟與算法柜架;
4、通過應(yīng)用范例學(xué)習(xí)貪心算法與回溯法的設(shè)計(jì)技巧與策略;
實(shí)驗(yàn)原理
1、貪心算法
貪心算法(又稱貪婪算法)是指,在對問題求解時,總是做出在當(dāng)前看來是最好的選擇。也就是說,不從整體最優(yōu)上加以考慮,他所做出的僅是在某種意義上的局部最優(yōu)解。貪心算法不是對所有問題都能得到整體最優(yōu)解,但對范圍相當(dāng)廣泛的許多問題他能產(chǎn)生整體最優(yōu)解或者是整體最優(yōu)解的近似解。
2、貪心算法的基本思想
建立數(shù)學(xué)模型來描述問題。把求解的問題分成若干個子問題。對每一子問題求解,得到子問題的局部最優(yōu)解。把子問題的解局部最優(yōu)解合成原來解問題的一個解。
3、回溯法
回溯法是一個既帶有系統(tǒng)性又帶有跳躍性的的搜索算法。它在包含問題的所有解的解空間樹中,按照深度優(yōu)先的策略,從根結(jié)點(diǎn)出發(fā)搜索解空間樹。算法搜索至解空間樹的任一結(jié)點(diǎn)時,總是先判斷該結(jié)點(diǎn)是否肯定不包含問題的解。如果肯定不包含,則跳過對以該結(jié)點(diǎn)為根的子樹的系統(tǒng)搜索,逐層向其祖先結(jié)點(diǎn)回溯。否則,進(jìn)入該子樹,繼續(xù)按深度優(yōu)先的策略進(jìn)行搜索。回溯法在用來求問題的所有解時,要回溯到根,且根結(jié)點(diǎn)的所有子樹都已被搜索遍才結(jié)束。而回溯法在用來求問題的任一解時,只要搜索到問題的一個解就可以結(jié)束。這種以深度優(yōu)先的方式系統(tǒng)地搜索問題的解的算法稱為回溯法,它適用于解一些組合數(shù)較大的問題。
4、回溯法的基本思想
確定了解空間的組織結(jié)構(gòu)后,回溯法就從開始結(jié)點(diǎn)(根結(jié)點(diǎn))出發(fā),以深度優(yōu)先的方式搜索整個解空間。這個開始結(jié)點(diǎn)就成為一個活結(jié)點(diǎn),同時也成為當(dāng)前的擴(kuò)展結(jié)點(diǎn)。在當(dāng)前的擴(kuò)展結(jié)點(diǎn)處,搜索向縱深方向移至一個新結(jié)點(diǎn)。這個新結(jié)點(diǎn)就成為一個新的活結(jié)點(diǎn),并成為當(dāng)前擴(kuò)展結(jié)點(diǎn)。如果在當(dāng)前的擴(kuò)展結(jié)點(diǎn)處不能再向縱深方向移動,則當(dāng)前擴(kuò)展結(jié)點(diǎn)就成為死結(jié)點(diǎn)。換句話說,這個結(jié)點(diǎn)不再是一個活結(jié)點(diǎn)。此時,應(yīng)往回移動(回溯)至最近的一個活結(jié)點(diǎn)處,并使這個活結(jié)點(diǎn)成為當(dāng)前的擴(kuò)展結(jié)點(diǎn)。回溯法即以這種工作方式遞歸地在解空間中搜索,直至找到所要求的解或解空間中已沒有活結(jié)點(diǎn)時為止。
運(yùn)用回溯法解題通常包含以下三個步驟:
針對所給問題,定義問題的解空間;確定易于搜索的解空間結(jié)構(gòu);以深度優(yōu)先的方式搜索解空間,并且在搜索過程中用剪枝函數(shù)避免無效搜索;
實(shí)驗(yàn)內(nèi)容:
1. 使用貪心算法解決最小生成樹問題。
2. 使用回溯法解決0-1背包問題。
3. 通過上機(jī)實(shí)驗(yàn)進(jìn)行貪心算法與回溯算法實(shí)現(xiàn)。
4. 保存和打印出程序的運(yùn)行結(jié)果,并結(jié)合程序進(jìn)行分析,上交實(shí)驗(yàn)報(bào)告。
實(shí)驗(yàn)代碼:
#include<iostream>
#include<cstring>
using namespace std
;int n
, m
;
int map
[101][101];int pre
[101];
int u
[101], v
[101], edge
[101]; int find(int x
)
{int root
= x
;while (pre
[root
] != root
)root
= pre
[root
];return root
;
}void prim()
{int count
= 0;cout
<< "prim下解為:" << endl
;int dist
[101]; int closest
[101]; bool s
[101];for (int i
= 1; i
<= n
; i
++) {dist
[i
] = map
[1][i
];s
[i
] = false;closest
[i
] = 1;}s
[1] = true;for (int i
= 1; i
< n
; i
++) {int min
= 100000;int k
= 1;for (int j
= 2; j
<= n
; j
++) {if ((dist
[j
] < min
) && (!s
[j
])){min
= dist
[j
];k
= j
;}}cout
<< k
<< "," << closest
[k
] << ":" << min
<< endl
;count
+= min
;s
[k
] = true;for (int j
= 1; j
<= n
; j
++){if ((map
[k
][j
] < dist
[j
]) && (!s
[j
])) {dist
[j
] = map
[k
][j
];closest
[j
] = k
;}}}cout
<< "最小權(quán)重和為:" << count
<< endl
;
}void kruskal()
{cout
<< "kruskal下解為:" << endl
;int minnum
, fu
, fv
;int count
= 0;int total
= n
- 1;while (total
> 0){int min
= 10000000;for (int i
= 1; i
<= m
; i
++) {if (u
[i
] == -1 || v
[i
] == -1)continue;if (edge
[i
] < min
){min
= edge
[i
];minnum
= i
;}}fu
= find(u
[minnum
]);fv
= find(v
[minnum
]);if (fu
!= fv
) {cout
<< v
[minnum
] << "," << u
[minnum
] << ":" << edge
[minnum
] << endl
;count
+= edge
[minnum
];pre
[fu
] = fv
;total
--;}edge
[minnum
] = 100000000; u
[minnum
] = -1;v
[minnum
] = -1;}cout
<< "最小權(quán)重和為:" << count
<< endl
;
}int main()
{cout
<< "輸入結(jié)點(diǎn)個數(shù)以及邊條數(shù):" << endl
;cin
>> n
>> m
;int i
, a
, b
, tem
;memset(map
, 0x3f, sizeof(map
)); cout
<< "輸入對應(yīng)兩結(jié)點(diǎn)序號以及兩點(diǎn)間邊的權(quán)重:" << endl
;for (i
= 1; i
<= n
; i
++) pre
[i
] = i
;for (i
= 1; i
<= m
; i
++){cin
>> a
>> b
;cin
>> tem
;map
[a
][b
] = map
[b
][a
] = tem
;u
[i
] = a
;v
[i
] = b
;edge
[i
] = tem
;}prim();kruskal();return 0;
}
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std
;
#define N 100010
int n
;
double c
;
double cw
= 0.0;
double cp
= 0.0;
double bestp
= 0.0;
int put
[100];
struct Edge
{double perp
;int order
;double v
;double w
;Edge() {};Edge(double a
, int b
, double c
, double d
) {perp
= a
;order
= b
;v
= c
;w
= d
;}bool operator <(const Edge
& S
)const {return perp
> S
.perp
;}
}e
[N
];
void knapsack()
{int i
, j
;for (i
= 1; i
<= n
; i
++)e
[i
].perp
= e
[i
].v
/ e
[i
].w
;sort(e
+ 1, e
+ n
);
}
void backtrack(int i
)
{double bound(int i
);if (i
> n
){bestp
= cp
;return;}if (cw
+ e
[i
].w
<= c
){cw
+= e
[i
].w
;cp
+= e
[i
].v
;put
[i
] = 1;backtrack(i
+ 1);cw
-= e
[i
].w
;cp
-= e
[i
].v
;}if (bound(i
+ 1) > bestp
)backtrack(i
+ 1);
}
double bound(int i
)
{double leftw
= c
- cw
;double b
= cp
;while (i
<= n
&& e
[i
].w
<= leftw
){leftw
-= e
[i
].w
;b
+= e
[i
].v
;i
++;}if (i
<= n
)b
+= e
[i
].v
/ e
[i
].w
* leftw
;return b
;
}
int main()
{int i
;cout
<< "請輸入物品的數(shù)量和背包的容量:" << endl
;cin
>> n
>> c
;cout
<< "請依次輸入" << n
<< "個物品的重量:" << endl
;for (i
= 1; i
<= n
; i
++) {cin
>> e
[i
].w
;e
[i
].order
= i
;}cout
<< "請依次輸入" << n
<< "個物品的價(jià)值:" << endl
;for (i
= 1; i
<= n
; i
++) {cin
>> e
[i
].v
;}knapsack();backtrack(1);printf("最優(yōu)價(jià)值為:%.2lf\n", bestp
);printf("需要裝入的物品編號是:");for (i
= 1; i
<= n
; i
++){if (put
[i
] == 1)cout
<< e
[i
].order
<<" ";}return 0;
}
實(shí)驗(yàn)結(jié)果:
總結(jié)
以上是生活随笔為你收集整理的C++——《算法分析》实验叁——贪心算法与回溯法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。