日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++——《算法分析》实验叁——贪心算法与回溯法

發(fā)布時間:2025/3/15 c/c++ 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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]; //u,v分別為兩個點(diǎn),edge為兩個點(diǎn)之間的邊int find(int x) {int root = x;while (pre[root] != root)root = pre[root];return root; }void prim() //最小生成樹 prim算法 {int count = 0;cout << "prim下解為:" << endl;int dist[101]; //lowcost[i]存樹中點(diǎn)到i點(diǎn)的邊的權(quán)值最小為多少int closest[101]; //closest[i]存放樹中哪個點(diǎn)到i點(diǎn)的邊的權(quán)值最小是哪個bool s[101];for (int i = 1; i <= n; i++) //初始化lowcost和s{dist[i] = map[1][i];s[i] = false;closest[i] = 1;}s[1] = true;for (int i = 1; i < n; i++) //最小生成樹只有n-1條邊{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])) //如果新的結(jié)點(diǎn)到j(luò)的邊比原來的結(jié)點(diǎn)到j(luò)的邊小,就用新結(jié)點(diǎn)替換掉原結(jié)點(diǎn){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) //不連通,就連接兩個點(diǎn){cout << v[minnum] << "," << u[minnum] << ":" << edge[minnum] << endl;count += edge[minnum];pre[fu] = fv;total--;}edge[minnum] = 100000000; //改變已經(jīng)找到的最小值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)容還不錯,歡迎將生活随笔推薦給好友。