算法竞赛3-11换抵挡装置的三种解法

题目:给出两个长度分别为n1和n2(n1、n2≤100)且每列高度只为1或2的长条。需要将它们放入一个高度为3的容器,问能够容纳它们的最短容器长度。

一、动态规划(只需输入两个长条的长度,系统自动寻找每列高度的最佳位置)

涉及知识点:

1.动态规划:是一种算法设计技术,用于解决具有重叠子问题和最优子结构性质的问题。在该问题中我们使用动态规划来找到放置长条的最短容器长度。

2.三维数组:我们使用一个三维数组dp来存储中间结果。涉及到如何初始化数组,以及如何访问和更新数组里的元素。

源码:

#include<stdio.h>
#include<string.h>
#include<limits.h>

int min(int a, int b) {
    return a < b ? a : b;
}

int main() {
    int n1, n2;
    scanf("%d %d", &n1, &n2); //输入两个长条的长度

    int dp[101][101][8]; // 创建一个三维数组dp,其中dp[i][j][k] 
    /* 表示放置前i个长条和前j个长条在一起,容器第k列的高度和。初始化所有值为INT_MAX*/
     /*数组dp的维度是101*101*8,意味着它可以存储最多100个长条放置的情况。因为高度只能为1和2,所以共有8种组合*/
    for (int i = 0; i <= n1; i++) {
        for (int j = 0; j <= n2; j++) {
            for (int k = 0; k < 8; k++) {
                dp[i][j][k] = INT_MAX;
            }
        }
    }
    dp[0][0][0] = 0;

    // 三重循环遍历所有可能的长条放置组合
    // 对于每个i和j,我们有两种高度h1和h2.尝试将这两种高度放在容器的每一列并更新dp[i][j][k] 为放置这两种高度的最小可能值。
    for (int i = 1; i <= n1; i++) {
        for (int j = 1; j <= n2; j++) { // 修正了循环条件中的括号错误
            for (int k = 0; k < 8; k++) {
                int h1 = 1, h2 = 2;

                // 需要考虑以下几种情况来更新dp[i][j][k]
                // 尝试将长条1的高度为h1放在容器第k列
                if (k >= h1)
                    dp[i][j][k] = min(dp[i][j][k], dp[i - 1][j][k - h1] + h1);
                //在尝试将长条1的第i个元素放到第k列时比较前i-1个元素和k-1列,谁少放谁,以下同理
                // 尝试将长条1的高度为h2放在容器第k列
                if (k >= h2)
                    dp[i][j][k] = min(dp[i][j][k], dp[i - 1][j][k - h2] + h2);
                // 尝试将长条2的高度为h1放在容器第k列
                if (k >= h1)
                    dp[i][j][k] = min(dp[i][j][k], dp[i][j - 1][k - h1] + h1);
                // 尝试将长条2的高度为h2放在容器第k列
                if (k >= h2)
                    dp[i][j][k] = min(dp[i][j][k], dp[i][j - 1][k - h2] + h2);
            }
        }
    }
    // 输出结果
    printf("最短容器长度为:%d\n", dp[n1][n2][0]);
    return 0;
}

(额我尝试了很多遍这个代码好像存在栈溢出还是什么其他的问题输出的结果总是一个很大的固定的数我也没办法了)

二、贪心算法

源码:

#include <stdio.h>

int minContainerLength(int n1, int n2, int bar1[], int bar2[]) {
    int length = 0; // 当前容器的长度
    int height = 0; // 当前容器中第i列的高度
    int i = 0, j = 0; // 分别用于遍历bar1和bar2的索引

    // 当两个长条都没有遍历完时
    while (i < n1 && j < n2) {
        // 如果bar1[i]的高度为1,且容器当前高度小于2,则可以将bar1[i]放入容器
        if (bar1[i] == 1 && height < 2) {
            height += bar1[i];
            i++;
        }
        // 如果bar2[j]的高度为1,且容器当前高度小于2,则可以将bar2[j]放入容器
        else if (bar2[j] == 1 && height < 2) {
            height += bar2[j];
            j++;
        }
        // 如果容器当前高度为2,则容器长度加1,高度清零,进入下一列
        else if (height == 2) {
            length++;
            height = 0;
        }
        // 如果容器当前高度为3,则容器长度加1,高度清零,进入下一列
        else if (height == 3) {
            length++;
            height = 0;
        }
    }

    // 处理剩余的长条
    while (i < n1) {
        if (height + bar1[i] <= 3) {
            height += bar1[i];
            i++;
        }
        else {
            length++;
            height = 0;
        }
    }

    while (j < n2) {
        if (height + bar2[j] <= 3) {
            height += bar2[j];
            j++;
        }
        else {
            length++;
            height = 0;
        }
    }

    // 如果最后一列的高度不为0,容器长度需要再加1
    if (height > 0) {
        length++;
    }

    return length;
}

int main() {
    int n1, n2;
    printf("请输入两个长条的长度(n1, n2):");
    scanf("%d %d", &n1, &n2);

    int bar1[n1], bar2[n2];
    printf("请输入第一个长条每列的高度(共%d列):", n1);
    for (int i = 0; i < n1; i++) {
        scanf("%d", &bar1[i]);
    }

    printf("请输入第二个长条每列的高度(共%d列):", n2);
    for (int i = 0; i < n2; i++) {
        scanf("%d", &bar2[i]);
    }

    int minLength = minContainerLength(n1, n2, bar1, bar2);
    printf("能够容纳它们的最短容器长度为:%d\n", minLength);

    return 0;
}

(喵的这个运行说不是常数)

三、我的思想(需要自己定义两个长条每列的高度)

我认为该题的关键在于n1如何放置能够使得n1和n2对应的元素相加恰都≤3,则也许可以从n1[0]开始尝试,n1和n2元素对应相加,此时若所有元素之和都≤3则说明该容器能容纳两个长条且长度为n1+n1后面所有元素为0时对应的n2的长度。否则n1向后移动一位,接着相加尝试……直到找到能容纳两个长条的位置并加以计算容器的长度,否则容器长度为最坏情况就是n1长度+n2长度

源码:

#include<stdio.h>
#include<limits.h>
int minContainerLength(int n1, int n2, int bar1[], int bar2[]) {
    int minLength = INT_MAX;//初始化最小长度为最大整数
    //尝试从bar1的不同位置开始放置
    for (int start = 0; start < n1; start++) {
        int sum = 0;//当前列的和
        int i = start, j = 0;//设置bar1和bar2的起始索引
        int currentLength = 0;//当前尝试的容器长度
        //遍历两个长条,直到找到不能放置的位置或遍历完至少一个长条
        while (i < n1 && j < n2) {
            //计算当前列的和
            sum += bar1[i] + bar2[j];
            //如果当前列的和超过三,则终止本次尝试并进行下一次尝试
            if (sum > 3) {
                break;
            }
            //移动到下一列
            i++;
            j++;
            currentLength++;//增加当前尝试的容器长度
        }
        //如果成功放置了两个长条,则更新最小长度
        if (i == n1 && j == n2 && sum <= 3) {
            minLength = currentLength;
        }
    }
    //如果没有找到合适的位置,返回n1加n2(最坏情况)
    return minLength = INT_MAX?n1 + n2:minLength;
}
int main(){
    int n1, n2;
    printf("请输入两个长条的长度:");
    scanf("%d %d", &n1, &n2);
    int bar1[n1],bar2[n2];
    printf("请输入第一个长条每列的高度:");
    for (int i = 0; i < n1; i++) {
        scanf("%d", &bar1[i]);
        printf("请输入第二个长条每列的高度:");
        for (int j = 0; j < n2; j++) {
            scanf("%d", &bar2[j]);
        }
        int minLength = minContainerLength(n1, n2, bar1, bar2);
        printf("能够容纳它们的最短容器长度为:%d\n",minLength);
        return 0;

    }
}

(这个运行也说表达式不是常数。。怎么就不是常数了。。。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值