国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

算法設(shè)計(jì)與分析-期末復(fù)習(xí)經(jīng)典例題

這篇具有很好參考價(jià)值的文章主要介紹了算法設(shè)計(jì)與分析-期末復(fù)習(xí)經(jīng)典例題。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

1.概述

1.1 算法的概念

算法設(shè)計(jì)應(yīng)滿足的目標(biāo):正確性,可使用,可讀,健壯,高效率,低存儲
算法的5個(gè)重要特征:有限、確定、可行、輸入、輸出
通常用函數(shù)的返回值表示算法能否正確執(zhí)行,如果某個(gè)形參需要將執(zhí)行結(jié)果回傳給實(shí)參,需要將該形參設(shè)計(jì)為引用型參數(shù)

1.2 算法分析

算法分析是分析算法占用計(jì)算機(jī)資源的情況
算法分析的兩個(gè)主要方面是分析算法的時(shí)間復(fù)雜度空間復(fù)雜度

1.3 時(shí)間復(fù)雜度

一層循環(huán):

  1. 列出循環(huán)趟數(shù)t與每趟循環(huán)i的變化值
  2. 找出t與i的關(guān)系(公式什么的)
  3. 找出循環(huán)結(jié)束條件
  4. 聯(lián)立兩式,解方程

算法設(shè)計(jì)與分析期末考試,算法,數(shù)據(jù)結(jié)構(gòu)算法設(shè)計(jì)與分析期末考試,算法,數(shù)據(jù)結(jié)構(gòu)算法設(shè)計(jì)與分析期末考試,算法,數(shù)據(jù)結(jié)構(gòu)

兩層循環(huán)

  1. 列出外層循環(huán)i的變化值
  2. 列出內(nèi)層語句的執(zhí)行次數(shù)
  3. 內(nèi)層語句執(zhí)行次數(shù)*外層循環(huán)次數(shù)=結(jié)果
    算法設(shè)計(jì)與分析期末考試,算法,數(shù)據(jù)結(jié)構(gòu)算法設(shè)計(jì)與分析期末考試,算法,數(shù)據(jù)結(jié)構(gòu)算法設(shè)計(jì)與分析期末考試,算法,數(shù)據(jù)結(jié)構(gòu)

多層循環(huán)
方法1. 抽象為計(jì)算三維體積
方法2. 列式求和
算法設(shè)計(jì)與分析期末考試,算法,數(shù)據(jù)結(jié)構(gòu)

1.4 空間復(fù)雜度

能不遞歸就不遞歸,遞歸占用的空間和時(shí)間復(fù)雜度太高了

循環(huán)占用的空間至始至終都是那個(gè),但遞歸每次的函數(shù)空間都是新創(chuàng)的,就是不能重復(fù)利用。

2.選擇題

  • 衡量一個(gè)算法好壞的標(biāo)準(zhǔn)是(C )。
    A 運(yùn)行速度快 B 占用空間少 C 時(shí)間復(fù)雜度低 D 代碼短

  • 二分搜索算法是利用( A )實(shí)現(xiàn)的算法。
    A、分治策略 B、動態(tài)規(guī)劃法 C、貪心法 D、回溯法

  • 以下不可以使用分治法求解的是(D )。
    A 棋盤覆蓋問題 B 選擇問題 C 歸并排序 D 0/1背包問題

  • 實(shí)現(xiàn)循環(huán)賽日程表利用的算法是( A )。
    A、分治策略 B、動態(tài)規(guī)劃法 C、貪心法 D、回溯法

  • 實(shí)現(xiàn)棋盤覆蓋算法利用的算法是( A )。
    A、分治法 B、動態(tài)規(guī)劃法 C、貪心法 D、回溯法

  • 實(shí)現(xiàn)合并排序利用的算法是( A )。
    A、分治策略 B、動態(tài)規(guī)劃法 C、貪心法 D、回溯法

  • 使用分治法求解不需要滿足的條件是(A )。
    A 子問題必須是一樣的 B 子問題不能夠重復(fù)C 子問題的解可以合并 D 原問題和子問題使用相同的方法解

  • 下列不是動態(tài)規(guī)劃算法基本步驟的是( A )。
    A、找出最優(yōu)解的性質(zhì) B、構(gòu)造最優(yōu)解 C、算出最優(yōu)解 D、定義最優(yōu)解

  • 下列是動態(tài)規(guī)劃算法基本要素的是( D )。
    A、定義最優(yōu)解 B、構(gòu)造最優(yōu)解 C、算出最優(yōu)解 D、子問題重疊性質(zhì)

  • 最長公共子序列算法利用的算法是( B )。
    A、分支界限法 B、動態(tài)規(guī)劃法 C、貪心法 D、回溯法

  • 實(shí)現(xiàn)最大子段和利用的算法是( B )。
    A、分治策略 B、動態(tài)規(guī)劃法 C、貪心法 D、回溯法

  • 矩陣連乘問題的算法可由( B)設(shè)計(jì)實(shí)現(xiàn)。
    A、分支界限算法 B、動態(tài)規(guī)劃算法 C、貪心算法 D、回溯算法

  • 下列算法中通常以自底向上的方式求解最優(yōu)解的是( B )。
    A、備忘錄法 B、動態(tài)規(guī)劃法 C、貪心法 D、回溯法

  • 最大效益優(yōu)先是( A )的一搜索方式。
    A、分支界限法 B、動態(tài)規(guī)劃法 C、貪心法 D、回溯法

  • 下面不是分支界限法搜索方式的是( D )。
    A、廣度優(yōu)先 B、最小耗費(fèi)優(yōu)先 C、最大效益優(yōu)先 D、深度優(yōu)先

  • 廣度優(yōu)先是( A )的一搜索方式。
    A、分支界限法 B、動態(tài)規(guī)劃法 C、貪心法 D、回溯法

  • 一個(gè)問題可用動態(tài)規(guī)劃算法或貪心算法求解的關(guān)鍵特征是問題的( B )。
    A、重疊子問題 B、最優(yōu)子結(jié)構(gòu)性質(zhì) C、貪心選擇性質(zhì) D、定義最優(yōu)解

  • 貪心算法與動態(tài)規(guī)劃算法的主要區(qū)別是( B )。
    A、最優(yōu)子結(jié)構(gòu) B、貪心選擇性質(zhì) C、構(gòu)造最優(yōu)解 D、定義最優(yōu)解

  • ( D )是貪心算法與動態(tài)規(guī)劃算法的共同點(diǎn)。
    A、重疊子問題 B、構(gòu)造最優(yōu)解 C、貪心選擇性質(zhì) D、最優(yōu)子結(jié)構(gòu)性質(zhì)

  • 背包問題的貪心算法所需的計(jì)算時(shí)間為( B )。
    A、O(n2n) B、O(nlogn) C、O(2n) D、O(n)

  • 0-1背包問題的回溯算法所需的計(jì)算時(shí)間為( A )
    A、O(n2n) B、O(nlogn) C、O(2n) D、O(n)

  • 下列算法中通常以深度優(yōu)先方式系統(tǒng)搜索問題解的是( D )。
    A、備忘錄法 B、動態(tài)規(guī)劃法 C、貪心法 D、回溯法

  • 下面是貪心算法的基本要素的是( C )。
    A、重疊子問題 B、構(gòu)造最優(yōu)解 C、貪心選擇性質(zhì) D、定義最優(yōu)解

  • 下面問題(B )不能使用貪心法解決。
    A 單源最短路徑問題 B N皇后問題 C 最小花費(fèi)生成樹問題 D 背包問題

  • 下列算法中不能解決0/1背包問題的是(A )
    A 貪心法 B 動態(tài)規(guī)劃 C 回溯法 D 分支限界法

  • 回溯法解TSP問題時(shí)的解空間樹是( A )。
    A、子集樹 B、排列樹 C、深度優(yōu)先生成樹 D、廣度優(yōu)先生成樹

  • 回溯法的效率不依賴于下列哪些因素( D )
    A.滿足顯約束的值的個(gè)數(shù) B. 計(jì)算約束函數(shù)的時(shí)間
    C. 計(jì)算限界函數(shù)的時(shí)間 D. 確定解空間的時(shí)間

  • 下面哪種函數(shù)是回溯法中為避免無效搜索采取的策略( B )
    A.遞歸函數(shù) B.剪枝函數(shù) C.隨機(jī)數(shù)函數(shù) D.搜索函數(shù)

  • 以深度優(yōu)先方式系統(tǒng)搜索問題解的算法稱為 ( D ) 。
    A、分支界限算法 B、概率算法 C、貪心算法 D、回溯算法

  • 回溯法搜索狀態(tài)空間樹是按照(C )的順序。
    A 中序遍歷 B 廣度優(yōu)先遍歷 C 深度優(yōu)先遍歷 D 層次優(yōu)先遍歷

3.分治法

3.1 快速排序 (*)

#include <stdio.h>

#define SIZE 6

//快速排序
void quick_sort(int num[], int low, int high )
{
    int i,j,temp; //temp是用來當(dāng)找到i和j并且i!=j時(shí)交換i和j的值 
    int tmp; //tmp用來保存基準(zhǔn)數(shù) 

    i = low; //num[low]也是基準(zhǔn)數(shù) 
    j = high;
    tmp = num[low];   //任命為中間分界線,左邊比他小,右邊比他大,通常第一個(gè)元素是基準(zhǔn)數(shù)

    if(i > j)  //如果下標(biāo)i大于下標(biāo)j,函數(shù)結(jié)束運(yùn)行,這個(gè)一般出現(xiàn)在以分界線為軸之后,左邊或者把右邊只有一個(gè)數(shù) 
    {
        return;
    }

    while(i != j)
    {
        while(num[j] >= tmp && j > i)   
        {
            j--;
        }

        while(num[i] <= tmp && j > i)
        {
            i++;
        }

        if(j > i)
        {
            temp = num[j];
            num[j] = num[i];
            num[i] = temp;
        }
    }

	// 直到i==j時(shí) 
    num[low] = num[i];
    num[i] = tmp;

    quick_sort(num,low,i-1);
    quick_sort(num,i+1,high);
}

int main()
{
    //創(chuàng)建一個(gè)數(shù)組
    int num[SIZE];
    int i;

    //輸入數(shù)字
    for(i =0; i < SIZE; i++)
    {
        scanf("%d",&num[i]);
    }

    quick_sort(num, 0, SIZE-1);

    for(i = 0; i < SIZE; i++)
    {
        printf(" %d ", num[i]);
    }

    return 0;
}

 

移動方法:

  1. 在數(shù)組中選一個(gè)基準(zhǔn)數(shù)tmp(通常為數(shù)組第一個(gè));
  2. 數(shù)組中設(shè)置兩個(gè)哨兵i(初始指向數(shù)組第一個(gè))和j(初始指向數(shù)組最后一個(gè));
  3. 先移動j,一次一次往前移,直到找到比tmp小的值(j>=tmp時(shí)都要往前移);
  4. 再移動i,一次一次往后移,直到找到比tmp大的值(i<=tmp時(shí)都要往后移);
  5. 當(dāng)找到符合條件的i和j的值時(shí),i和j對應(yīng)的值互換,但是i和j指向的位置沒變;
  6. 當(dāng)i=j時(shí),將i與tmp的值互換,i指向的位置沒變;
  7. 體現(xiàn)分治的地方來了:此時(shí),以i指向的數(shù)作為軸,分開左右兩部分,每部分再按照上面的7個(gè)步驟再來一遍。

學(xué)習(xí)引用-快速排序

4.蠻力法

4.1 任務(wù)分配問題 (*)

問題描述:假設(shè)有n個(gè)任務(wù)需要分配給n個(gè)人執(zhí)行,每個(gè)任務(wù)只分配給一個(gè)人,每個(gè)人只分配一個(gè)任務(wù),且第j個(gè)任務(wù)分配給第i個(gè)人的成本是C[i,> j](1≤i , j≤n),任務(wù)分配問題要求找出總成本最小的分配方案。
算法設(shè)計(jì)與分析期末考試,算法,數(shù)據(jù)結(jié)構(gòu)

用蠻力法解決任務(wù)分配生成成本矩陣,成本矩陣中相應(yīng)元素相加來求得每種分配方案的總成本

相應(yīng)解釋看代碼

#include <iostream>
#include <cstring>

using namespace std;

int visit[11],num[11];
int n,value = 9999999;
int martrix[4][4];
int lowNum[11]; 
/*檢驗(yàn)數(shù)據(jù)
4
9 2 7 8
6 4 3 7
5 8 1 8
7 6 9 4
*/

// 這個(gè)函數(shù)用于每一次在確定了num數(shù)組之后進(jìn)行對應(yīng)的總成本計(jì)算 
void findLowCost() {
	int sum = 0;
	for(int i = 1; i <= n; i++) {
		sum += martrix[i - 1][num[i] - 1];
	}
	if(sum < value) {
		for(int i=1;i<=n;i++){
			lowNum[i]=num[i];
		}
		value = sum;
	}
}
/*
visit代表當(dāng)前i任務(wù)是否被選擇 
i的取值:1,2,3,4;代表任務(wù)種類 
num數(shù)組代表人員,
num[length]:里面的length代表第幾個(gè)人,用1,2,3,4區(qū)分,共四個(gè)人 
*/
void dfs(int length) {
	if(length > n) {
		findLowCost();
	} else {
		for(int i = 1; i <= n; i++) {
			if(visit[i] == 0) {
				visit[i] = 1; //visit[i]=1代表當(dāng)前i任務(wù)是否被選擇
				num[length] = i; //num[length] = i代表第length個(gè)人選擇了第i個(gè)任務(wù) 
				dfs(length + 1);
				visit[i] = 0; 
				//visit[i]重新置為0,代表在一次分配方案之后
				//(就是每個(gè)人都分配到一種任務(wù),每個(gè)任務(wù)只分配給一個(gè)人) 
				//當(dāng)length > n進(jìn)行了findLowCost函數(shù)之后,回退至length=n-1,以為length==n的那個(gè)循環(huán)已經(jīng)走完了 
				//在 length=n-1時(shí),visit置0,,但還有一個(gè)i需要走循環(huán),這又是一個(gè)方案
				// 依次循環(huán)回退走完所有方案。 
			}
		}
	}
}


int main() {
	cin >> n;
	memset(visit,0,sizeof(visit)); //visit全置為0,代表任務(wù)全沒被選擇 
	for(int i = 0; i < 4; i++) {
		for(int j = 0; j < 4; j++) {
			cin >> martrix[i][j];
		}
	}

	
	dfs(1);
	cout<<"最小成本分配方案:"<<endl;
	for(int i=1;i<=n;i++){
		cout<<"第"<<i<<"個(gè)人選擇的任務(wù)是:"<<lowNum[i]<<endl;
	}
	cout << "最小成本:" <<value;
	
	return 0;
}

學(xué)習(xí)引用-任務(wù)分配蠻力法

5.回溯法

5.0 回溯法的概念

在搜索嘗試過程中尋找問題的解,當(dāng)發(fā)現(xiàn)已不滿足求解條件時(shí)(設(shè)置的判斷條件稱為“剪枝函數(shù)”),就往回移動(回溯),嘗試別的路徑

回溯法思路的簡單描述是:把問題的解空間轉(zhuǎn)化成了圖或者樹的結(jié)構(gòu)表示,然后使用深度優(yōu)先搜索策略進(jìn)行遍歷,遍歷的過程中記錄和尋找所有可行解或者最優(yōu)解。

與分支限界法的聯(lián)系:使用剪枝函數(shù)的深度優(yōu)先生成狀態(tài)空間樹中的節(jié)點(diǎn)的求解方法稱為回溯法;廣度優(yōu)先生成結(jié)點(diǎn),并使用剪枝函數(shù)的方法稱為分枝限界法

5.1 裝載問題 (*)

  1. 問題描述:現(xiàn)有 n 件貨物 (Cargo) 每件貨物的重量(weight)是 Wi ( 0<i≤n , i∈ N ), 需要把這 n 件貨物全部裝上兩艘船 shipOne 和 shipTwo , 兩艘船的最大容量為Capacity1 和 Capacity2 問是否有一種合理的方案使得全部貨物都能裝上船?
  2. 代碼
package com.ljh;

class Cargo {

    int weight = 0; //貨物重量
    boolean isLoad = false; //貨物是否被裝載上船狀態(tài)

}

class Ship {

    int capacity = 0; //船的容量
    int minMargin;    //目前得到的最小余量(不斷縮小)-就是剩余的船的容量的最小值
    int nowMargin; //現(xiàn)在的船上余量
    int nowWeight; //現(xiàn)在船上貨物的重量
    int numOfCargo; //船上貨物數(shù)量
    Cargo[] cargo;
    Cargo[] realCargo;

    public Ship(int capacity) {
        this.capacity = capacity;
        this.minMargin = capacity;
        this.nowMargin = capacity;
    }

    //這里使用重載是為了區(qū)分兩艘船的作用.
    public Ship(int capacity, Cargo cargo[], Cargo realCargo[]) {
        this.capacity = capacity;
        this.cargo = cargo;
        this.realCargo = realCargo;
        this.numOfCargo = cargo.length; //初始化時(shí)船上的貨物個(gè)數(shù)=總貨物個(gè)數(shù)
        this.minMargin = capacity;
        this.nowMargin = capacity;
        this.nowWeight = 0;
    }

}

public class BackTrackAlgorithm {

    //聲明全部所需的變量,我們需要裝載的貨物重量,它的總重量,兩艘船,貨物對象.

    static int aboutCargo[] = {90, 80, 40, 30, 20, 12, 10};
    static int totalWeight;
    static Ship shipOne;
    static Ship shipTwo;
    static Cargo[] cargo = new Cargo[aboutCargo.length]; //聲明cargo數(shù)組
    static Cargo[] realCargo = new Cargo[aboutCargo.length];  //不用先思考readlCargo的作用在后面會給出解釋
    static int i = 0;    //見后


    //在main中直接調(diào)用兩個(gè)方法得出解
    public static void main(String[] args) {

        BackTrackAlgorithm bta = new BackTrackAlgorithm();
        bta.init();
        bta.getResult();


    }

    //初始化船,并使用回溯法,使得我們的問題得出最優(yōu)方案
    public void init() {

        for (int j = 0; j < aboutCargo.length; j++) {
            cargo[j] = new Cargo();
            realCargo[j] = new Cargo();
            realCargo[j].weight = aboutCargo[j];
            cargo[j].weight = aboutCargo[j];
            totalWeight += aboutCargo[j]; //計(jì)算總的貨物重量
        }

        shipOne = new Ship(152, cargo, realCargo); //這里代表我先以shipOne做考慮
        shipTwo = new Ship(130);

        //開始建立樹結(jié)構(gòu)
        while (true) {
            //進(jìn)行每一輪的選擇
            while (i < shipOne.numOfCargo) {
                if ((shipOne.nowWeight + shipOne.cargo[i].weight) <= shipOne.capacity) {//判斷條件
                    shipOne.nowWeight += shipOne.cargo[i].weight;//變化當(dāng)前重量
                    shipOne.nowMargin -= shipOne.cargo[i].weight;//變化當(dāng)前余量
                    shipOne.cargo[i].isLoad = true;//確認(rèn)i貨物裝載上船
                    i += 1;
                } else {
                    shipOne.cargo[i].isLoad = false;//不裝載,繼續(xù)往下走
                    i += 1;
                }
            }
            //經(jīng)過上面已經(jīng)得到shipOne的一個(gè)方案

            //進(jìn)行一輪的選擇之后是否得到更優(yōu)的方案
            //這里改變r(jià)ealCargo[j].isLoad才是代表真正最優(yōu)方案
            if (shipOne.nowMargin < shipOne.minMargin) {

                shipOne.minMargin = shipOne.nowMargin;
                //如果得到更優(yōu)的方案,我們需要存入這一輪的貨物選擇情況,為什么要使用另一個(gè)realCargo數(shù)組,請閱讀代碼后思考片刻
                for (int j = 0; j < shipOne.numOfCargo; j++) {
                    if (shipOne.cargo[j].isLoad == true) {
                        shipOne.realCargo[j].isLoad = true;
                    }
                    if (shipOne.cargo[j].isLoad == false) {
                        shipOne.realCargo[j].isLoad = false;
                    }
                }
            }

            //進(jìn)入回溯法,回溯的就是我們之前設(shè)置的靜態(tài)屬性 i 即我們選擇的貨物貨號
            i = backtrace(i - 1);//為什么是 i-1:i-1才是判斷的最后一個(gè)貨物貨號

            //退出的條件,我們是否已經(jīng)結(jié)束最后一輪.
            if (i == 0) {
                return;
            }
        }


    }

    //回溯法
    public int backtrace(int j) {
        //請讀者思考作用.
        while (j > 0 && shipOne.cargo[j].isLoad == false) {
            j -= 1;
        }
        //請讀者思考作用.
        if (shipOne.cargo[j].isLoad == true) {
            shipOne.cargo[j].isLoad = false;
            shipOne.nowMargin += shipOne.cargo[j].weight;
            shipOne.nowWeight -= shipOne.cargo[j].weight;

            j += 1;
        }
        return j;

        /**
         *  tips:這里每輪的回溯會改變shipOne.cargo[i].isLoad,最后得到的自然是最后一輪選擇方案,
         *  但最后一輪得到的不一定是最優(yōu)解,所以我們肯定需要另外一個(gè)Cargo數(shù)組來記錄更優(yōu)方案 即前面
         *  聲明的readCargo[]
         */
    }

    //返回最優(yōu)結(jié)果集
    public void getResult() {
        //判斷是否有解
        if ((totalWeight - (shipOne.capacity - shipOne.minMargin)) <= shipTwo.capacity) {

            System.out.println("\n本問題有合理的方案.\n");

            for (int j = 0; j < aboutCargo.length; j++) {
                if (shipOne.realCargo[j].isLoad == true) {
                    System.out.println("貨物 " + j + " 已經(jīng)裝載上船1,重量是:" + shipOne.realCargo[j].weight);
                }
                if(shipOne.realCargo[j].isLoad==false) {
                    System.out.println("貨物 " + j + " 將會裝載上船2,重量是:" + shipOne.realCargo[j].weight);
                }
            }
        } else {
            System.out.println("經(jīng)過努力的嘗試,得出本問題沒有合理的方案使得全部貨物裝上兩艘船,抱歉");
        }

    }

}

解題思路:
回溯法是將問題的 解 抽象成 圖或者的結(jié)構(gòu)來表示.
在裝載問題中,對于每個(gè)貨物我們的選擇只有 選擇 / 不選 所以我們選擇抽象成樹的結(jié)構(gòu),對于選擇此貨物自然對應(yīng) 1/true
對于不選擇此貨物對應(yīng) 0/true , 依次對每個(gè)貨物進(jìn)行選擇,我們自然會得到 2^n個(gè)解 但是我們當(dāng)然沒有必要把所有結(jié)果都列舉出來,
例如以下例子 :

W 為貨物的重量的集合c1,c2為兩艘船的總?cè)萘?設(shè)置判斷條件為: 已經(jīng)裝上的 貨物重量 加上 下一個(gè)貨物
后的重量不大于shipOne的容量,那么就可以裝上此貨物 .若大于則選擇不裝此貨物 這樣自然就可以得到一棵得到 優(yōu)化結(jié)果集的子樹 .

但是經(jīng)過第一輪的選擇之后,雖然得到了第一個(gè)方案,但是我們不能保證這是最優(yōu)的解 , 不能確定是最優(yōu)的方案就不能保證我們的問題是否有解 ,
所以只有經(jīng)過多輪不同的選擇 才能得到最優(yōu)的方案,才能得出問題是否有解.

那么 , 如何進(jìn)行多輪的選擇? 怎么才能知道 哪一輪選擇的方案是最好的? 前面提到余容量就是我們判斷是否是更優(yōu)方案的指標(biāo)
剩余容量越小,則說明這樣的方案更優(yōu).

知道如何判斷是否是更優(yōu)的方案之后,我們就要思考如何遍歷這棵樹能更快的得出結(jié)果集,如果從頭開始遍歷,自然是效率最低選擇,因?yàn)槲覀儠貜?fù)走我們已經(jīng)走過的路.
所以我們不妨進(jìn)行回溯, 如下圖所示: 我們第一輪得出的結(jié)果是

90+0+40+0+20+0+0 ,于是從最后一個(gè)貨物 ( 重量為10的貨物開始回溯 ) 對于已經(jīng)選擇為 0/false
的物品我們自然不需要再去遍歷它的左子樹了,因?yàn)槲覀儽旧砭脱b不下它 . 所以我們?nèi)ケ闅v右子樹 . 于是我們往上回溯 ,
找到以第一個(gè)我們已經(jīng)選擇的貨物 ,我們這一輪 ( 第二輪從選擇重量為20的貨物開始 ) 就不裝載 重量為 20的貨物,
我們想要去選擇剩下的其余貨物(12 和 10).進(jìn)行第二輪的選擇后 會得到一個(gè)解決方案,我們自然就可以比較 余量(Margin)
是否較前一種方案更優(yōu) 接著我們繼續(xù)回溯…一直到我們進(jìn)行最后一輪回溯 , 最后一輪便是從我們之前選擇的第一個(gè)貨物開始,一來就不裝載 (
重量為90的貨物 ) 此貨物. 最后進(jìn)行一輪選擇. 最后就可以得到我們的最優(yōu)方案 , 以此便可以確定我們的問題 , 是否有解.

左子樹有值代表選中,左子樹為0代表未選中
算法設(shè)計(jì)與分析期末考試,算法,數(shù)據(jù)結(jié)構(gòu)

學(xué)習(xí)引用-裝配問題回溯法

6.分支限界法

6.1 流水作業(yè)調(diào)度問題 (*)

問題描述:有n個(gè)作業(yè)(編號為1~n)要在由兩臺機(jī)器M1和M2組成的流水線上完成加工。每個(gè)作業(yè)加工的順序都是先在M1上加工,然后在M2上加工。M1和M2加工作業(yè)i所需的時(shí)間分別為ai和bi(1≤i≤n)。
流水作業(yè)調(diào)度問題要求確定這n個(gè)作業(yè)的最優(yōu)加工順序,使得從第一個(gè)作業(yè)在機(jī)器M1上開始加工,到最后一個(gè)作業(yè)在機(jī)器M2上加工完成所需的時(shí)間最少??梢约俣ㄈ魏巫鳂I(yè)一旦開始加工,就不允許被中斷,直到該作業(yè)被完成,即非優(yōu)先調(diào)度

關(guān)鍵公式:對于按1~n順序執(zhí)行的某種調(diào)度方案,f1表示在M1上執(zhí)行完當(dāng)前第i步的作業(yè)對應(yīng)的總時(shí)間,f2數(shù)組表示在M2上執(zhí)行完當(dāng)前第i步的作業(yè)的總時(shí)間。
若第i步執(zhí)行作業(yè)j,計(jì)算公式如下:
f1=f1+a[j];
f2[i]=max(f1,f2[i-1])+b[j]

代碼:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define INF 999999
#define	MAX 5

using namespace std;

//問題表示
int n=4; //作業(yè)數(shù)
int a[MAX]={0,5,10,9,7};//M1上的執(zhí)行時(shí)間,不用下標(biāo)0的元素
int b[MAX]={0,7,5,9,8};//M2上的執(zhí)行時(shí)間,不用下標(biāo)0的元素
//求解結(jié)果表示
int bestf=INF;//存放最優(yōu)調(diào)度時(shí)間
int bestx[MAX];//存放當(dāng)前作業(yè)最佳調(diào)度
int total=1;//結(jié)點(diǎn)個(gè)數(shù)累計(jì)

struct NodeType//隊(duì)列結(jié)點(diǎn)類型
{
    int no;//結(jié)點(diǎn)編號
    int x[MAX];//x[i]表示第i步分配作業(yè)編號
    int y[MAX];//y[i]=1表示編號為i的作業(yè)已經(jīng)分配
    int i;//步驟編號
    int f1;//f1表示在M1上執(zhí)行完當(dāng)前第i步的作業(yè)對應(yīng)的總時(shí)間
    int f2;//f2表示在M2上執(zhí)行完當(dāng)前第i步的作業(yè)的總時(shí)間
    int lb;//下界
    bool operator<(const NodeType &s) const//重載<關(guān)系函數(shù)
    {
        return lb>s.lb;//lb越小越優(yōu)先出隊(duì)
    }
};

void bound(NodeType &e)//求結(jié)點(diǎn)e的限界值
{
    int sum=0;
    for(int i=1;i<=n;i++)//掃描所有作業(yè)
    {
        if(e.y[i]==0) //編號為i的作業(yè)未分配
        {
            sum+=b[i];//僅累計(jì)e.x中還沒有分配的作業(yè)的在M2上的執(zhí)行時(shí)間
        }
    }
    e.lb=e.f1+sum;
}

void bfs()//求解流水作業(yè)調(diào)度問題
{
    NodeType e,e1; priority_queue<NodeType> qu;//定義優(yōu)先隊(duì)列
    memset(e.x,0,sizeof(e.x));//初始化根結(jié)點(diǎn)的x
    memset(e.y,0,sizeof(e.y));//初始化根結(jié)點(diǎn)的y
    e.i=0;//根結(jié)點(diǎn)
    e.f1=0;
    e.f2=0;
    bound(e);
    e.no=total++;
    qu.push(e);//根結(jié)點(diǎn)進(jìn)隊(duì)列
    while(!qu.empty())
    {
        e=qu.top();
        qu.pop(); //出隊(duì)結(jié)點(diǎn)e
        if(e.i==n) //達(dá)到葉子結(jié)點(diǎn)
        {
            if(e.f2<bestf) //比較求最優(yōu)解
            {
                bestf=e.f2;
                for(int j1=1;j1<=n;j1++)
                {
                    bestx[j1]=e.x[j1];//在第j1步分配對應(yīng)的作業(yè) 
                }
            }
        }
        e1.i=e.i+1;//擴(kuò)展分配下一個(gè)步驟的作業(yè),對應(yīng)結(jié)點(diǎn)e1
        for(int j=1;j<=n;j++)//考慮所有的n個(gè)作業(yè)
        {
            if(e.y[j]==1)
            {
                continue;//作業(yè)j是否已分配,若已分配,跳過
            }
            //若作業(yè)j還未被分配: 
            for(int i1=1;i1<=n;i1++)//復(fù)制e.x得到e1.x
            {
                e1.x[i1]=e.x[i1];
            }
            for(int i2=1;i2<=n;i2++)//復(fù)制e.y得到e1.y
            {
                e1.y[i2]=e.y[i2];
            }
            e1.x[e1.i]=j;//為第i步分配作業(yè)j
            e1.y[j]=1;//表示作業(yè)j已經(jīng)分配
            e1.f1=e.f1+a[j];//求f1=f1+a[j]
            e1.f2=max(e.f2,e1.f1)+b[j];//求f[i+1]=max(f2[i],f1)+b[j]
            bound(e1);
            if(e1.f2<=bestf)//剪枝,剪去不可能得到更優(yōu)解的結(jié)點(diǎn)
            {
                e1.no=total++;//結(jié)點(diǎn)編號增加1
                qu.push(e1);
            }
        }
    }
}

int main()
{
	bfs();
	cout<<"Optimal plan is :"<<endl;
	for(int k=1;k<=n;k++)
    {
        cout<<"The "<<k<<" step is to execute the job is :"<<bestx[k]<<endl;
    }
	cout<<"The total time is :"<<bestf<<endl;
	return 0;
}

 

學(xué)習(xí)引用-流水作業(yè)分支界限法

7.貪心法

7.0 貪心算法的理解

貪心算法并不從整體最優(yōu)上加以考慮,所作出的僅是某種意義上的局部最優(yōu)選擇,要確定一個(gè)問題是否適合使用貪心算法解題,必須證明每一步所做的貪心選擇最終導(dǎo)致問題的整體最優(yōu)解

7.1 活動安排問題 (*)

由于輸入的活動是以其完成時(shí)間升序排列的,所以每次總是選擇具有最早完成時(shí)間的活動加入集合 selected

代碼:

#include <stdio.h>
#define N 100

/*檢驗(yàn)數(shù)據(jù)
11
1 4
3 5
0 6
5 7
3 8
5 9
6 10
8 11
8 12
2 13
11 14
*/
/*
n:活動個(gè)數(shù)
s:開始時(shí)間數(shù)組
t:結(jié)束時(shí)間數(shù)組
selected:活動選擇數(shù)組 
*/
void greedyselector(int n, int s[], int f[], int selected[])
{
	int i;
	int j = 1; //j記錄最近一次加入到a中的活動 
	
	selected[1] = 1; //首先選擇活動1 
	for (i = 2; i <= n; i ++)
		if (s[i] >= f[j]) { //如果活動i與活動j兼容,則選擇活動i 
		// 兼容性的判斷:下一個(gè)活動的開始時(shí)間>=上一個(gè)活動的結(jié)束時(shí)間 
			selected[i] = 1;
			j = i;
		}
		else
			selected[i] = 0;
}

int main()
{
	int s[N], f[N]; //s[i],f[i]存儲活動 i的開始和結(jié)束時(shí)間
	int selected[N]; //若活動 i被選擇,則selected[i]置1,否則置0
	int n,i;
	
	printf("請輸入活動個(gè)數(shù):");
	scanf("%d", &n);
	
	printf("請輸入各個(gè)活動的開始和結(jié)束時(shí)間(要求按結(jié)束時(shí)間升序輸入):\n");
	for (i = 1; i <= n; i ++) //從i=1開始掃描 
		scanf("%d%d", &s[i], &f[i]);
		
	greedyselector(n, s, f, selected);
	printf("如下活動被選擇:\n");
	for (i = 1; i <= n; i ++)
		if (selected[i] == 1)
			printf("%d ", i);
			
	printf("\n");
	return 0;
} 


學(xué)習(xí)引用-活動安排貪心算法

8.動態(tài)規(guī)劃法

8.0 什么是動態(tài)規(guī)劃:

動態(tài)規(guī)劃是一種解決多階段決策問題的優(yōu)化方法,把多階段過程轉(zhuǎn)化為一系列單階段問題

8.1 0/1背包問題 (*)

這個(gè)問題是有個(gè)前提條件:就是每個(gè)物品你最多只能拿一次(也就是說一個(gè)物品你要嗎不拿就是拿0次,拿就只能拿1次,所以叫0/1問題)

遞推樹算法設(shè)計(jì)與分析期末考試,算法,數(shù)據(jù)結(jié)構(gòu)

狀態(tài)轉(zhuǎn)移方程算法設(shè)計(jì)與分析期末考試,算法,數(shù)據(jù)結(jié)構(gòu)

代碼:

package com.ljh;


public class package01_DP {
    /**
     * 0-1背包
     *
     * @param val    價(jià)值
     * @param weight 重量
     * @param W      背包容量
     * @return 最優(yōu)解
     */
    public static int MaxValueWithDP(int[] val, int[] weight, int W) {
        int N = weight.length;   //物品數(shù)
        // 創(chuàng)建背包矩陣,矩陣的行數(shù)是物品數(shù)量+1;矩陣的列數(shù)是物品重量+1
        int[][] V = new int[N + 1][W + 1];

        //初始化矩陣第一行,背包容量為0
        for (int col = 0; col <= W; col++) {
            V[0][col] = 0;
        }
        //初始化矩陣第一列,背包容量為0
        for (int row = 0; row <= N; row++) {
            V[row][0] = 0;
        }
        for (int i = 1; i <= N; i++) {  //一行一行填充值,i = 1從第二行開始填
            for (int j = 1; j <= W; j++) {  //一列一列填充值,j = 1從第二列開始填
                if (weight[i - 1] <= j) {  //如果當(dāng)前物品重量小于等于背包中的當(dāng)前重量 i為1是,weight[0]是第一個(gè)物品的重量
                    /*比較不加入該物品時(shí)該重量的最大價(jià)值(前一行)V[i - 1][j]
                     *與
                     *當(dāng)前物品的價(jià)值val[i - 1]+沒放該物品之前,背包已有重量的最大價(jià)值V[i - 1][j - weight[i - 1]]
                     */
                    V[i][j] = Math.max(val[i - 1] + V[i - 1][j - weight[i - 1]], V[i - 1][j]);
                } else { //如果當(dāng)前物品重量大于背包中的當(dāng)前重量
                    V[i][j] = V[i - 1][j];  //直接使用前一行的最優(yōu)解
                }
            }
        }
        // 打印矩陣
        for (int[] rows : V) {
            for (int col : rows) {
                System.out.format("%5d", col);
            }
            System.out.println();
        }
        return V[N][W];

    }


    public static void main(String[] args) {
        int val[] = {3, 4, 5, 8}; //物品價(jià)值數(shù)組
        int weight[] = {2, 3, 4, 5}; //物品重量數(shù)組
        int W = 8; //背包重量
        int MaxValue = MaxValueWithDP(val, weight, W);
        System.out.println("當(dāng)前背包的最大價(jià)值是:" + MaxValue);


    }
}

根據(jù)代碼做出動態(tài)轉(zhuǎn)移表算法設(shè)計(jì)與分析期末考試,算法,數(shù)據(jù)結(jié)構(gòu)

學(xué)習(xí)引用-0/1背包問題動態(tài)規(guī)劃法文章來源地址http://www.zghlxwxcb.cn/news/detail-772376.html

到了這里,關(guān)于算法設(shè)計(jì)與分析-期末復(fù)習(xí)經(jīng)典例題的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 算法設(shè)計(jì)與分析 期末復(fù)習(xí) 北郵BUPT

    算法設(shè)計(jì)與分析 期末復(fù)習(xí) 北郵BUPT

    以下內(nèi)容以“算法設(shè)計(jì)與分析-2022”王曉茹老師的ppt為大綱 問題、要求 也均為老師課堂上的口述要求和ppt上的要求 漸進(jìn)上界、漸進(jìn)下界 證明 O ( f ( n ) ) + O ( g ( n ) ) = O ( m a x { f ( n ) , g ( n ) } ) O(f(n))+O(g(n)) = O(max{f(n),g(n)}) O ( f ( n )) + O ( g ( n )) = O ( ma x { f ( n ) , g ( n )}) (最后一

    2024年01月16日
    瀏覽(16)
  • 計(jì)算機(jī)算法設(shè)計(jì)與分析期末復(fù)習(xí)

    計(jì)算機(jī)算法設(shè)計(jì)與分析期末復(fù)習(xí)

    以下是我的部分算法筆記,希望可以給復(fù)習(xí)的小伙伴們參考一下: 題目: 一切合法的輸入數(shù)據(jù)都能得出滿足要求的結(jié)果,包括典型的、苛刻的輸入數(shù)據(jù)也能夠得出滿足要求的結(jié)果。這個(gè)含義對應(yīng)算法的(正確性) 算法要對異常情況進(jìn)行適當(dāng)?shù)奶幚?,就是算法的(健壯性?/p>

    2024年02月13日
    瀏覽(19)
  • 【期末復(fù)習(xí)】計(jì)算機(jī)算法設(shè)計(jì)與分析

    小編相信大家都很急切,要如何短時(shí)間學(xué)會算法通過考試呢?下面就讓樓主帶大家一起了解吧。 算法期末考試,其實(shí)就是算法期末考試了。那么小編為什么會算法期末考試,相信大家都很好奇是怎么回事。大家可能會感到很驚訝,小編怎么會算法期末考試呢?但事實(shí)就是這樣

    2024年02月03日
    瀏覽(64)
  • NJUPT算法分析與設(shè)計(jì)期末考試202.12.1

    NJUPT算法分析與設(shè)計(jì)期末考試202.12.1

    用書:計(jì)算機(jī)算法設(shè)計(jì)與分析(第五版) 判斷10題30分 簡答5題30分 算法設(shè)計(jì)4*10=40分 1.程序、算法、軟件是不完全等價(jià)的。 2.最優(yōu)化問題不是都可以用動態(tài)規(guī)劃來求解,使用動態(tài)規(guī)劃要滿足(子問題間有依賴關(guān)系;有最優(yōu)子結(jié)構(gòu))。 3.分治策略是先把復(fù)雜的問題自頂向下求解

    2024年02月07日
    瀏覽(25)
  • 算法設(shè)計(jì)與分析期末復(fù)習(xí)題(史上最詳細(xì))

    算法設(shè)計(jì)與分析期末復(fù)習(xí)題(一) 1、二分搜索算法是利用( A )實(shí)現(xiàn)的算法。 A、分治策略 B、動態(tài)規(guī)劃法 C、貪心法 D、回溯法 2、下列不是動態(tài)規(guī)劃算法基本步驟的是( A )。 A、找出最優(yōu)解的性質(zhì) B、構(gòu)造最優(yōu)解 C、算出最優(yōu)解 D、定義最優(yōu)解 3、最大效益優(yōu)先是( A )的一

    2023年04月09日
    瀏覽(24)
  • 山東大學(xué)軟件學(xué)院算法設(shè)計(jì)與分析期末考試回憶版

    山東大學(xué)軟件學(xué)院算法設(shè)計(jì)與分析期末考試回憶版

    2021年12月13日上午10:10-12:10 本次考試是山東大學(xué)軟件學(xué)院2019級軟件工程專業(yè)大三上算法期末考試 本學(xué)期的算法課上課時(shí)間為2-7周,9-14周(實(shí)際上13周就結(jié)束了),第15周考試 考試范圍:除了并查集和35章近似算法不考,其他在老師PPT上的內(nèi)容都是考試范圍 本次算法考試一共有

    2024年02月10日
    瀏覽(27)
  • 數(shù)據(jù)庫期末復(fù)習(xí)(SQL,范式,數(shù)據(jù)庫設(shè)計(jì)例題)

    數(shù)據(jù)庫期末復(fù)習(xí)(SQL,范式,數(shù)據(jù)庫設(shè)計(jì)例題)

    創(chuàng)表 視圖 例題:建立一個(gè)視圖V1,顯示老師與學(xué)生的授課關(guān)系,包括年份,學(xué)期,課程名稱,老師ID,老師姓名,學(xué)生ID,學(xué)生姓名 向表中添加或刪除約束 添加信息 例題:給“Aufr”同學(xué)選上2010年秋季學(xué)期的所有課程 刪除信息 例題:刪除“Comp. Sci.”學(xué)院“Ploski”同學(xué),所有

    2024年02月02日
    瀏覽(31)
  • C++程序設(shè)計(jì)期末考試復(fù)習(xí)試題及解析 3(自用~)

    C++程序設(shè)計(jì)期末考試復(fù)習(xí)試題及解析 3(自用~)

    可以很清楚看到淺拷貝所造成的錯誤:在析構(gòu)的時(shí)候會重復(fù)析構(gòu),這是由于淺拷貝時(shí),b的buffer指針和a的buffer指針指向的是同一片空間 如何更改? 換為深拷貝! 即棄用默認(rèn)拷貝構(gòu)造函數(shù),自己寫一個(gè)拷貝構(gòu)造函數(shù) 改為深拷貝后,a、b對象不會相互影響,由于b未調(diào)用set()函

    2024年02月09日
    瀏覽(19)
  • 【數(shù)據(jù)結(jié)構(gòu)與算法】第七章-圖【期末復(fù)習(xí)】

    【數(shù)據(jù)結(jié)構(gòu)與算法】第七章-圖【期末復(fù)習(xí)】

    圖:有向圖、網(wǎng),無向圖、網(wǎng)。 頂點(diǎn) 邊:有向圖圖稱作弧,分弧頭弧尾。 依附:邊依附點(diǎn),邊和點(diǎn)關(guān)聯(lián) 鄰接:點(diǎn)鄰接點(diǎn) 度:點(diǎn)關(guān)聯(lián)的邊的數(shù)目 完全圖: 無向: C n 2 C_n^2 C n 2 ? 條邊; 有向: 2 C n 2 2C_n^2 2 C n 2 ? 條邊 連通:若干結(jié)點(diǎn)互相可以通信,用手提起一個(gè)結(jié)點(diǎn)可以順

    2024年02月01日
    瀏覽(20)
  • 數(shù)據(jù)結(jié)構(gòu)與算法期末復(fù)習(xí)——知識點(diǎn)+題庫

    數(shù)據(jù)結(jié)構(gòu)與算法期末復(fù)習(xí)——知識點(diǎn)+題庫

    (1)數(shù)據(jù):所有能被計(jì)算機(jī)識別、存儲和處理的符號的集合(包括數(shù)字、字符、聲音、圖像等信息 )。 (2)數(shù)據(jù)元素:是數(shù)據(jù)的基本單位,具有完整確定的實(shí)際意義。在計(jì)算機(jī)程序中通常作為一個(gè)整體進(jìn)行考慮和處理。一個(gè)數(shù)據(jù)元素可由若干個(gè)數(shù)據(jù)項(xiàng)組成。 (3)數(shù)據(jù)項(xiàng):構(gòu)成數(shù)據(jù)元

    2024年02月12日
    瀏覽(31)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包