算法设计与分析期末复习

参考书籍:

2025年1月3日期末考试题型:

一、选择题(20%)

二、填空(40%)

  • 归并排序:循环体的条件,传参的范围
  • 回溯算法:if条件,循环体条件,回溯语句(上下对称)

三、编程(40%)

考试范围:

第二章  二分搜索 归并排序 快速排序  找第K小数
第三章  矩阵连乘  最长公共子序列 单调递增最长子序列 0-1背包
第四章  会场安排问题 程序存储问题 最短路问题 背包问题
第五章  0-1背包  旅行售货员 n后问题 子集和问题

2025年一月的编程大题:

  1. 贪心算法,可套模版:程序存储问题
  2. 求LCS_length,套模板,较简单,不同点再与输入的是两个数组,if条件改成a[i]+b[i]=0,即原来是相同,现在是互为相反数
  3. 回溯法,较难,可以套01背包的回溯法的模板(定义结构体,按重量价值比给物品排序),不同点是物品的结构更复杂,如何存储输入的数据(结构体包含书本的名称,重量,价值)如何记录回溯的结果

选择题20分

  • 动态规划的两个特征
  • 贪心算法的两个特征
  • 时间复杂度的计算
  • 给f(x),g(x)表达式,判断是否同阶,上界,下界(第一章课后习题)
  • 给代码判断时间复杂度
  • NP类问题:是指一类可以用不确定性多项式算法求解的判定问题。
  • 分支界限法和回溯法的区别,是广度优先搜索还是深度优先搜索

编程题:范围2-5章

1.递归分治——归并排序

挖空点:if(),while(),Merge(),MergeSort()括号内的条件/参数


 

2.贪心算法——程序存储问题

题目:设有n 个程序{1,2,…, n}要存放在长度为L的磁带上。程序i存放在磁带上的长度是 li,1≤i≤n。 程序存储问题要求确定这n个程序在磁带上的一个存储方案,使得能够在磁带上存储尽可能多的程序。 对于给定的n个程序存放在磁带上的长度,计算磁带上最多可以存储的程序数。

输入格式:

第一行是2 个正整数,分别表示文件个数n和磁带的长度L。接下来的1行中,有n个正整数,表示程序存放在磁带上的长度。

输出格式:

输出最多可以存储的程序数。

输入样例:

6 50

2 3 13 8 80 20

输出样例:

5

贪心策略:优先选择存放在磁带上长度最短的程序存储 

#include <iostream>
#include <algorithm>
using namespace std;

int main() {
	int n;
	int l;
	cin >> n >> l; 
	int* lens = new int[n+1];
	for (int i = 0; i < n; i++) {
		cin >> lens[i];
	}
	
	//程序长度从小到大排序 
	sort(lens, lens + n);  //lens表示开始元素地址
	
	int count = 0;
	//每次选择长度短的程序,直到磁带存不下 
	for (int i = 0; i < n; i++) {
		if (l < lens[i]) break;	
		l -= lens[i];
		count++;
	}
	cout << count;
	return 0;
}

3.动态规划——最长公共子序列

#include <iostream>
#include <string>
using namespace std;

int c[1000][1000]; //c[i][j]用来存储 Xi到Yj的最长公共子序列长度 

void MaxLength(int m, int n, string x, string y) { //m,n分别表示字符串x和字符串y的长度 
    int i, j; 
    for (i = 0; i <= m; i++) // 当j为0的时候,空序列是Xi到Yj的最长公共子序列,所以赋值0,注意这里i从0开始
        c[i][0] = 0;
    for (i = 0; i <= n; i++) // 当x为0的时候,空序列是Xi到Yj的最长公共子序列,所以赋值0,注意这里i从0开始
        c[0][i] = 0;
    for (i = 1; i <= m; i++) {  
        for (j = 1; j <= n; j++) { 
            if (x[i - 1] == y[j - 1]) {  // 索引要减1,因为字符串从0开始
                c[i][j] = c[i - 1][j - 1] + 1;
            } else {
                c[i][j] = max(c[i - 1][j], c[i][j - 1]); 
            }
        }
    } 
}

int main() {
    string x, y;
    cin >> x >> y;
    int m = x.length();  // 得到字符串x的长度 
    int n = y.length();   // 得到字符串y的长度 
    MaxLength(m, n, x, y); 
    int precent = 0; 
    if (c[m][n]!= 0) {
        precent = (c[m][n] * 100) / min(m, n);
    }
    cout << "公共长度:" << c[m][n] << endl; 
    return 0;
}

4.回溯法——0-1背包

给定n(n<=100)种物品和一个背包。物品i的重量是wi,价值为vi,背包的容量为C(C<=1000)。问:应如何选择装入背包中的物品,使得装入背包中物品的总价值最大? 在选择装入背包的物品时,对每种物品i只有两个选择:装入或不装入。不能将物品i装入多次,也不能只装入部分物品i。
输入格式:
共有n+1行输入: 第一行为n值和c值,表示n件物品和背包容量c; 接下来的n行,每行有两个数据,分别表示第i(1≤i≤n)件物品的重量和价值。
输出格式:
输出装入背包中物品的最大总价值。
输入样例:

5 10
2 6
2 3
6 5
5 4
4 6

输出样例: 

15

#include <iostream>
#include <algorithm>
using namespace std;
struct Obj {
        int weight;
        int value;
};
int cp = 0, cw = 0, maxValue = 0;
int n, c;
Obj* objs;

//限界函数
float bound(int i) {
        int cleft = c - cw;
        int b = cp;
        while (i <= n && objs[i].weight < cleft) {
                b+= objs[i].value;
                cleft -= objs[i].weight;
                i++;
        }
        if (i <= n) {
                b += objs[i].value * cleft / objs[i].weight;
        }
        return b;
}

//递归回溯函数
void backtrack(int t) {
        if (t > n) {//叶子结点,得到问题的一个可能解
                if (cp > maxValue) {
                        maxValue = cp;
                }
                return;
        }
        
        //如果满足约束条件进入左子树
        if (cw + objs[t].weight <= c) { 
                cw += objs[t].weight;
                cp += objs[t].value;
                backtrack(t + 1);
                cw -= objs[t].weight;
                cp -= objs[t].value;
        }
        //如果满足限界条件进入右子树
        if (bound(t + 1) > maxValue)
                backtrack(t + 1);
}

//用于排序的比较函数,单位价值高的排在前面
bool cmp(Obj obj1, Obj obj2) {
        if (float(obj1.value) / obj1.weight > float(obj2.value) / obj2.weight)
                return true;
        else
                return false;
}

int main() {
        int i;
        cin >> n >> c;
        objs = new Obj[n + 1];
        for (i = 1; i <= n; i++) {
                cin >> objs[i].weight>> objs[i].value;
        }
        sort(objs + 1, objs + n + 1, cmp);
        
        backtrack(1);
        cout << maxValue;
        return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值