作业比赛编号 : 1371 - 2023年春季学期《算法分析与设计》练习16

问题 A: 0-1背包问题(回溯法)

题目描述

有n个物品,第i个物品重量为wi,价值为vi,现有一背包容量为C,要求把物品装入背包得到最大价值,并且要求出这些选取的物品。 要求用回溯法求解。

输入

多组测试数据,请处理到文件尾,一个整数表示物品的数量n,后一行有n个整数,代表价值,再后一行有n个整数,代表重量,最后有一个整数C代表背包容量,1<=n<=15,1<=vi<=30,1<=wi<=30,1<=C<=80。

输出

背包的最大总价值和所选取的物品,如果选取的方案有多种,请输出字典序最小的那种方案,每组测试数据应输出一行,在这里字典序最小的意思是,我们假设存在两种不同方案S,T所能得到的总价值相同且是最大的,对于方案S种选取|S|种物品,方案T选取|T|种物品,对于i=1,2...j-1,我们有si = ti,但sj < tj,则方案的S的字典序比方案T的字典序要小。由于没有使用special judge,所以如果选取得方案是S,请按照从小到大的顺序输出方案S中的物品下标。

样例输入 Copy

5
6 3 6 5 4
2 2 4 6 5
8
样例输出 Copy
15 1 2 3
#include <stdio.h>
#include <stdlib.h>

#define MAX_N 15
#define MAX_V 30
#define MAX_W 30
#define MAX_C 80

int n, C, max_value;
int v[MAX_N], w[MAX_N], best_solution[MAX_N], c_solution[MAX_N];
int c_value, c_weigth;

void backtrack(int index, int cur_value, int cur_weight) {
    if (cur_weight > C) {
        return;
    }
    if (index == n) {
        if (cur_value > max_value) {
            max_value = cur_value;
            for (int i = 0; i < n; i++) {
                best_solution[i] = c_solution[i];
            }
        }
        return;
    }
    c_solution[index] = 1;
    backtrack(index + 1, cur_value + v[index], cur_weight + w[index]);
    c_solution[index] = 0;
    backtrack(index + 1, cur_value, cur_weight);
}

int main() {
    while (~scanf("%d", &n)) {
        for (int i = 0; i < n; i++) {
            scanf("%d", &v[i]);
        }
        for (int i = 0; i < n; i++) {
            scanf("%d", &w[i]);
        }
        scanf("%d", &C);
        max_value = 0;
        backtrack(0, 0, 0);
        printf("%d ", max_value);
        for (int i = 0; i < n; i++) {
            if (best_solution[i]) {
                printf("%d ", i + 1);
            }
        }
        printf("\n");
    }
    return 0;
}

问题 B: 旅行售货员(TSP)

题目描述

有若干个城市,任何两个城市之间的距离都是确定的,现要求一旅行商从某城市出发必须经过每一个城市且只在一个城市逗留一次,最后回到出发的城市,问如何事先确定一条最短的线路以保证路径最短?

输入

输入两个整数n,m分别代表城市数量,边数量,2<=n<=8,n-1<=m<=2*n
接下来m行每行输入有3个整数x,y,z代表x和y城市之间有一条长为z的路,保证输入的图是连通的,旅行商总是从1城市出发。

输出

要求求出最短的路径,和该路径的长度,如果不存在这样的路径你只需要输出-1。

样例输入 Copy
4 6
1 2 30
1 3 6
1 4 4
2 3 5
2 4 10
3 4 20
样例输出 Copy
1 3 2 4 1
25
#include <stdio.h>
#include <limits.h>

#define MAXN 8

int n, m, map[MAXN + 1][MAXN + 1], current[MAXN + 1], best[MAXN + 1];
int c_length, bestLength;
const int MAX = INT_MAX;

void backtrace(int t) {
    if (t == n) {
        if (map[current[n - 1]][current[n]] != MAX && map[current[n]][1] != MAX &&
            (c_length + map[current[n - 1]][current[n]] + map[current[n]][1] < bestLength || bestLength == -1)) {
            for (int i = 1; i <= n; i++) {
                best[i] = current[i];
            }
            bestLength = c_length + map[current[n - 1]][current[n]] + map[current[n]][1];
        }
        return;
    }
    for (int i = t; i <= n; i++) {
        if (map[current[t - 1]][current[i]] < MAX && (c_length + map[current[t - 1]][current[i]] < bestLength || bestLength == -1)) {
            int temp = current[t];
            current[t] = current[i];
            current[i] = temp;
            c_length = c_length + map[current[t - 1]][current[t]];
            backtrace(t + 1);
            c_length = c_length - map[current[t - 1]][current[t]];
            current[i] = current[t];
            current[t] = temp;
        }
    }
}

int Length(int n) {
    int i = 0;
    while (n) {
        i++;
        n = n / 10;
    }
    return i;
}

void swap(int a[], int i, int j) {
    int temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}

void copy(int c[], int d[], int s, int t) {
    for (int i = s; i <= t; i++)
        c[i] = d[i];
}

int main() {
    while (scanf("%d%d", &n, &m) == 2) {
        for (int i = 1; i <= n; i++) {
            current[i] = best[i] = i;
            for (int j = 1; j <= n; j++) {
                map[i][j] = MAX;
            }
        }
        c_length = bestLength = -1;
        for (int i = 0; i < m; i++) {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            map[x][y] = map[y][x] = z;
        }
        backtrace(2);
        if (bestLength == -1) {
            printf("-1\n");
        }
        else {
            for (int i = 1; i <= n; i++) {
                printf("%d ", best[i]);
            }
            printf("1\n%d\n", bestLength + 1);
        }
    }
    return 0;
}

问题 C: 挑选奖品

题目描述

X星人参加了一档幸运大抽奖节目,凭借无敌好运气中了一等奖。节目组给他准备了一个奖品箱,这个箱子中一共有M个格子,每个格子中只能放一个奖品。
现在一共有N个不同的奖品供X星人挑选,不同的奖品其价值不一定相等
“贪心的”X星人希望所挑选的奖品的价值和最大,需要你编写一个程序帮他计算出所能得到的最大价值和。

输入

单组输入。
第1行包含两个正整数M和N,分别表示奖品箱中格子的数量和奖品的总数。(1< M<=10^5且1<N<=10^5)
第2行包含N个正整数,分别表示N个奖品的价值,两两之间用空格隔开。

输出

奖品箱中所有奖品的最大价值和。

样例输入 Copy
3 5
1 3 2 6 5
样例输出 Copy
14
#include <stdio.h>
#include <stdlib.h>

// 快速排序
void quickSort(int arr[], int low, int high) {
    if (low < high) {
        int pivot = arr[high];
        int i = low - 1;
        for (int j = low; j <= high - 1; j++) {
            if (arr[j] < pivot) {
                i++;
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        int temp = arr[i + 1];
        arr[i + 1] = arr[high];
        arr[high] = temp;

        int p = i + 1;

        quickSort(arr, low, p - 1);
        quickSort(arr, p + 1, high);
    }
}

int main() {
    int n, m;
    while (scanf("%d %d", &n, &m) == 2) {
        int* arr = (int*)malloc(m * sizeof(int));
        for (int i = 0; i < m; i++) {
            scanf("%d", &arr[i]);
        }

        // 排序
        quickSort(arr, 0, m - 1);

        long sum = 0;
        for (int i = m - 1; i >= m - n && i >= 0; i--) {
            sum += arr[i];
        }

        printf("%ld\n", sum);

        free(arr);
    }

    return 0;
}

问题 D: 排列蛋卷

题目描述

刚考完研的TC同学这段时间在家闲得慌,因此他决定学点新手艺。今天他学习的内容是:做蛋卷。
由于是第一次做蛋卷,TC同学做出来蛋卷长短不一。看着这些长度都不一样的蛋卷,TC同学的强迫症又犯了。他希望能够拿出其中部分蛋卷,使得留下来的蛋卷能够按照长度从大到小的次序排列
请问他最少需要拿出多少根蛋卷

输入

单组输入,对于每一组测试数据,第1行N表示蛋卷的总数量(n<=1000)。 
第2行包含N个正整数,分别表示每一根蛋卷的长度。(单位:厘米) 
保证在同一组输入数据中每一根蛋卷的长度均不一样。

输出

输出最少需要拿出的蛋卷数量。

样例输入 Copy
5
15 18 17 11 12
样例输出 Copy
2
#include <stdio.h>
#include <stdlib.h>

int main() {
    int n;
    while (scanf("%d", &n) == 1) {
        int max = 0;
        int* arr = (int*)malloc((n + 5) * sizeof(int));
        int* b = (int*)malloc((n + 5) * sizeof(int));
        for (int i = 1; i <= n; i++)
            scanf("%d", &arr[i]);
        int maxlen;
        b[1] = 1;
        for (int i = 2; i <= n; i++) {
            maxlen = 0;
            for (int j = i - 1; j >= 1; j--) {
                if (arr[j] > arr[i] && b[j] > maxlen) {
                    maxlen = b[j];
                }
            }
            b[i] = maxlen + 1;
            if (max < b[i])
                max = b[i];
        }
        printf("%d\n", n - max);
        free(arr);
        free(b);
    }

    return 0;
}

问题 E: 最大收益

题目描述

小X是一位精明的投资人,他每次都能够做出正确的投资判断。
现在有N个项目,每个项目的总投资额和总收益已知,并且每一个项目都允许小X只投资一部分,当然也就只能拿到一部分收益。 
现在小X决定拿出M万元钱来进行投资,请你帮他设计一个算法来计算最大收益和

输入

单组输入,对于每一组数据,第1行包含两个正整数,分别是M和N,其中M<=10^6,N<=100。
接下来N行每行均包含两个正数(不一定是正整数),第1数字表示第N个项目的总投资额(万元),第2个数字表示第N个项目的总收益(万元),两个数字之间用空格隔开。 

输出

小X可以获得的最大收益和(万元,结果四舍五入保留两位小数)。

样例输入 Copy
100 4
50 10 
20 10 
40 10 
50 20
样例输出 Copy
37.50
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;

struct touzi {
    double w;
    double v;
    double vw;
};

int cmp(touzi& a, touzi& b) {
    return a.vw > b.vw;
}

int main() {
    double M;
    int N;
    while (~scanf("%lf%d", &M, &N)) {
        struct touzi t[105];
        for (int i = 0; i < N; i++) {
            scanf("%lf%lf", &t[i].w, &t[i].v);
            t[i].vw = t[i].v / t[i].w;
        }
        sort(t, t + N, cmp);
        double value = 0;
        int i = 0;
        while (t[i].w <= M && i < N) {
            M -= t[i].w;
            value += t[i].v;
            i++;
        }
        if (i < N) {
            value += M * t[i].vw;
        }
        printf("%.2lf\n", value);
    }
    return 0;
}

问题 F: X星人的基因

题目描述

X星人的基因由A、B、C、D、E五种不同的结构组合而成。
如果两个性别不同的X星人的基因序列相似度大于50%,按照X星的法律他们是禁止结婚的,等于50%据说还是可以的。
那么基因的相似度怎么计算呢?分别从两个人身上取长度均为N的基因片段,如果它们的最长公共子序列为M,则相似度=M/N。是不是很简单呢?
现在给你两段X星人的基因序列片段,请你判断他们是不是可以结婚?

输入

每一组测试数据包含3行,
第1行数字N表示待比较基因序列片段的长度,N<=10^3。
第2行和第3行为两个长度为N的基因序列片段。
输入0表示结束。

输出

两个X星人是否可以结婚,如果可以输出”Yes“,如果不可以输出”No“。

样例输入 Copy
8
A B C D E A B C
A C C D C B A E
6
A B C D E E
A E D C B B
0
样例输出 Copy
Yes
Yes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char a[2000];
char b[2000];
int dp[2000][2000];

void perm(char arr[], int k, int n) {
    int i, t;
    if (k == n) {
        for (i = 0; i <= n; i++) {
            printf("%c", arr[i]);
        }
        printf("\n");
    }
    for (i = k; i <= n; i++) {
        t = arr[k];
        arr[k] = arr[i];
        arr[i] = t;
        perm(arr, k + 1, n);
        t = arr[i];
        arr[i] = arr[k];
        arr[k] = t;
    }
}

int function(char a[], char b[], int n) {
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (a[i - 1] == b[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            }
            else {
                if (dp[i][j - 1] > dp[i - 1][j]) {
                    dp[i][j] = dp[i][j - 1];
                }
                else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
    }
    return dp[n][n];
}

void copy(int c[], int d[], int s, int t) {
    for (int i = s; i <= t; i++)
        c[i] = d[i];
}

int Length(int n) {
    int i = 0;
    while (n) {
        i++;
        n = n / 10;
    }
    return i;
}

void swap(int a[], int i, int j) {
    int temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}

int main() {
    int n;
    while (scanf("%d", &n) != EOF) {
        if (n == 0) {
            break;
        }
        getchar();
        for (int i = 0; i < n; i++) {
            scanf("%c", &a[i]);
            getchar();
        }
        for (int i = 0; i < n; i++) {
            scanf("%c", &b[i]);
            getchar();
        }
        int m = function(a, b, n);

        double percent = (double)m / n;

        if (percent <= 0.5) {
            printf("Yes\n");
        }
        else {
            printf("No\n");
        }
    }
    return 0;
}

问题 G: X星人的礼物

题目描述

六一儿童节到了,X星人宝宝收到了很多很多礼物。他决定把这些礼物装到自己的礼物箱中。为此,他准备了很多个型号相同的礼物箱,每个礼物箱能够装礼物的最大重量都是一样的。但是X星人宝宝不希望在一个礼物箱里面装太多礼物(可能担心礼物会被压坏吧),每个礼物箱最多只允许装2个礼物
假设X星人宝宝收到了N个礼物,现在给出每一个礼物的重量和一个礼物箱的最大装载量,请你编写一个程序计算X星人宝宝最少要用多少个礼物箱才能够把所有的礼物都装完

输入

单组输入。
每组两行,第1行输入两个正整数,分别表示礼物的数量N和每个礼物箱的最大装载量C,其中1<=N<=1000,1<=C<=100,两者之间用英文空格隔开。
第2行输入N个不超过100的正整数,分别表示每一个礼物的重量,两两之间用英文空格隔开。
输入保证最重的礼物的重量<=C。

输出

针对所输出的数据,输出将所有的礼物全部都装完所需的礼物箱的最少个数。

样例输入 Copy
5 80
20 70 40 30 10
样例输出 Copy
3
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

void quickSort(int arr[], int low, int high) {
    int i = low;
    int j = high;
    int pivot = arr[low + (high - low) / 2];

    while (i <= j) {
        while (arr[i] < pivot) {
            i++;
        }
        while (arr[j] > pivot) {
            j--;
        }
        if (i <= j) {
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
            i++;
            j--;
        }
    }

    if (low < j) {
        quickSort(arr, low, j);
    }
    if (i < high) {
        quickSort(arr, i, high);
    }
}

int main() {
    int n, c;
    scanf("%d%d", &n, &c);

    int* goods = (int*)malloc(n * sizeof(int));
    for (int i = 0; i < n; i++) {
        scanf("%d", &goods[i]);
    }

    quickSort(goods, 0, n - 1);

    int cnt = 0;
    int i = 0;
    int j = n - 1;

    while (i <= j) {
        if (goods[i] + goods[j] <= c) {
            cnt++;
            i++;
            j--;
        }
        else {
            cnt++;
            j--;
        }
    }

    if (i == j) {
        cnt++;
    }

    printf("%d\n", cnt);

    free(goods);

    return 0;
}

问题 H: X星人的股票

题目描述

X星人最近迷上了炒股,他炒股有个习惯,每次看到股票跌的时候就会买入
现在给出某只股票一段时间的股价,假如该股票每天最多只能买入一次,请你编写一个程序计算X星人最多可以买入几次该股票

输入

单组输入。
第1行输入一个正整数N表示某股票股价连续交易的天数。(1<=N<=1000)
第2行输入N个正整数表示该股票在N个连续交易日的股价,两两之间用英文空格隔开。(扩展知识:交易日是指股票交易发生的时间。常见的交易日时间是周一至周五,另外法定节假日和周末,股票市场和基金市场都是休市的。)

输出

请输出X星人最多可以买入股票的次数(不考虑第1次买入,只考虑中间买入的次数)。

样例输入 Copy
10
52 68 54 35 67 27 22 55 36 28
样例输出 Copy
4
#include <stdio.h>
#include <stdlib.h>

int main() {
    int n;
    scanf("%d", &n);

    int* nums = (int*)malloc(n * sizeof(int));
    for (int i = 0; i < n; i++) {
        scanf("%d", &nums[i]);
    }

    int* d = (int*)malloc(n * sizeof(int));
    for (int i = 0; i < n; i++) {
        d[i] = 1;
    }

    for (int i = 1; i < n; i++) {
        for (int j = 0; j < i; j++) {
            if (nums[i] < nums[j] && d[i] < d[j] + 1) {
                d[i] = d[j] + 1;
            }
        }
    }

    int maxD = 0;
    for (int i = 0; i < n; i++) {
        if (d[i] > maxD) {
            maxD = d[i];
        }
    }

    printf("%d\n", maxD - 1);

    free(nums);
    free(d);

    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值