南大算法设计与分析课程课后习题(1)

1.1

这里直接使用冒泡排序,并设置了变量保证在已经排好的情况下及时终止

void sort(vector<int>& v) {
    bool flag = true;
    for (int i = 0; i < v.size() && flag; ++i) {
        flag = false;
        for (int j = 0; j < v.size() - i - 1; ++j)
            if (v[j] > v[j + 1]) {
                swap(v[j], v[j + 1]);
                flag = true;
            }
    }
}

//这是测试用例
int main()
{
    vector<int> e = {7,6,5,4,3,2,1};
    sort(e);
    for (auto i : e)
        cout << i << endl;

    system("pause");
    return 0;
}
View Code

假设3个数为1,2,3。最坏情况是每次都要交换,需要3次比较。最好情况是每次都不需要交换,排序顺序为1,2,3,需要两次比较。假设每个输入的概率均等,3个数排列有6中情况,其中只有1,2,3的比较次数为2次,其他都是3次,平均情况为17/6

最坏情况下将3个数排序最少需要3次比较,假设数组元素为1、2、3,最坏情况为:第一次选取的两个数是1、3,第一次能判断前两个数的大小,第23次比较判断2的位置

1.2
假设3个数分别为a,b,c。拿a和b中更大的数和c去比较,如果c大于max(a,b),则返回max(a,b),否则返回max(c,min(a,b))
int searchmid(int a, int b, int c) {
    if (a < b) {
        if (b < c)
            return b;
        if (a < c)
            return c;
        else
            return a;
    }
    else {
        if (a < c)
            return a;
        if (c < b)
            return b;
        else
            return c;
    }
}
//这是测试用例
int main()
{
    cout << searchmid(3,1,2) << endl;

    system("pause");
    return 0;
}
View Code

最坏情况需要3次比较,最好情况需要两次比较,输入情况有6种,2种的比较次数为2,4种的比较次数为3,平均情况为8/3。

最坏情况下至少需要3次比较。

1.3

这个问题通俗点说就是子集集合要覆盖所有的元素且子集集合中元素个数要尽可能小

假设全集U={1,2,3,4,5},子集S1={1,2,4,5},S2={1,3,5},S3={3}。按照1中算法得出最小子集为S1和S2,但是应该为S1和S3。1中给出的应该是集合覆盖问题的贪心近似算法,近似但不完全准确。

 找了很多算法书,网上也看了一些,并没有发现有什么比较好的解决方案,这里直接写一个暴力解法吧,稍微优化了一下,总能得到最小覆盖,但效率很低。(优化思路:如果几个集合并起来不等于全集,那么这几个集合的子集的并也不可能等于全集,在穷举时从大集合逐步减小,减小到某个点能及时终止,减少无意义的穷举)

void subsetgenerate(set<int>& u, vector<set<int>>& subset, vector<vector<set<int>>>& result) {
    //将subset所有元素集中到一个集合之中
    set<int> temp;
    for (auto i : subset)
        for (auto j : i)
            temp.emplace(j);
    //如果subset包含了所有u的元素,加入结果集result中,并且去掉一个再做一次subsetgenerate判断
    if (temp.size() == u.size()) {
        result.emplace_back(subset);
        for (int i = 0; i < subset.size();++i) {
            set<int> s = subset[i];
            subset.erase(subset.begin()+i);
            subsetgenerate(u, subset,result);
            subset.insert(subset.begin()+i,s);
        }
    }
}
//主逻辑函数
vector<set<int>> setcover(set<int>& u, vector<set<int>>& subset) {
    vector<vector<set<int>>> result;
    subsetgenerate(u,subset,result);
    int s = INT_MAX;
    int pos = -1;
    //找出元素和最小的情况
    for (int i = 0; i < result.size(); ++i) {
        int num = 0;
        for (auto j : result[i])
            num += j.size();
        if (num < s)
            pos = i;
    }
    return result[pos];
}

//这是测试用例
int main()
{
    set<int> u = {1,2,3,4,5};
    set<int> s1 = {1,3,5};
    set<int> s2 = {2,4};
    set<int> s3 = {1,4};
    set<int> s4 = {2,5};
    vector<set<int>> subset = {s1,s2,s3,s4};
     auto result = setcover(u,subset);
    for (auto i : result) {
        for (auto j : i) {
            cout << j;
        }
        cout << endl;
    }

    system("pause");
    return 0;
}
View Code

1.4

第一个:s = {2,3,4,1},T=4时错误

vector<int> coin1(vector<int>& s, int sum) {
    vector<int> result;
    int n = 0;
    for (auto i : s) {
        n += i;
        result.emplace_back(i);
        if (n == sum)
            return result;
        if (n > sum)
            break;
    }
    vector<int> r;
    return r;
}
View Code

第二个:s = {2,3,4,1},T=4时错误

vector<int> coin2(vector<int>& s, int sum) {
    sort(s);
    vector<int> result;
    int n = 0;
    for (auto i : s) {
        n += i;
        result.emplace_back(i);
        if (n == sum)
            return result;
        if (n > sum)
            break;
    }
    vector<int> r;
    return r;
}
View Code

第三个:s = {2,3,4,1},T=5时错误

vector<int> coin3(vector<int>& s, int sum) {
    sort(s);
    vector<int> result;
    int n = 0;
    for (int i = s.size()-1; i > 0;--i) {
        n += s[i];
        result.emplace_back(s[i]);
        if (n == sum)
            return result;
        if (n > sum)
            break;
    }
    vector<int> r;
    return r;
}
View Code

1.5

数学归纳法证明

int horner(vector<int> ratio, int x) {
    int b = ratio[ratio.size()-1];
    for (int i = ratio.size() - 2; i >= 0; --i)
        b = ratio[i] + b * x;
    return b;
}
View Code

1.6

int c = 2;
int int_mult(int y, int z) {
    if (z == 0)
        return 0;
    else
        return int_mult(c * y, z/c) + y*(z%c);
}
View Code

c=2时的数学归纳法证明

  • 观察可得,z=0时算法成立
  • 假设z<=k是成立,考虑z=k+1的情况。当z=k+1时,恒有z/c<k成立,所以z=k+1时也成立。

c为任意一个不小于2的常数时,同样使用数学归纳法,使用c=2为先决条件去假设c=k时成立,在c=k+1同样重复重z=0到z=k+1的上述步骤。不再赘述

1.7

使用每个输入的概率乘以每一个输入的步数,得到期望

需要注意的是第三个概率要乘1/2,而且题目所给的概率之和加起来并不等于1,所以最后一个n的概率要用1来减

平均代价:1/n*10+2/n*20+1/4n*30+(1-1/n-2/n-1/4n)*n

原文地址:https://www.cnblogs.com/likaiming/p/8532226.html