算法分析课程设计第五题:5.毕业季(贪心算法、分治算法)摧毁积木

这篇博客介绍了如何解决一个计算机科学中的经典问题,即最少次数摧毁积木。作者提供了三种不同的编程语言实现——Java、Python和C++,通过递归和分治策略找到最优解。算法首先统计每行和每列的最大积木数量,然后选择破坏次数最少的方式进行操作,直至所有积木都被摧毁。文章详细阐述了算法思路和代码实现,适合对算法和数据结构感兴趣的读者深入理解。
摘要由CSDN通过智能技术生成
题目描述
羊驼 Luck 的寝室里有 n 堆积木,每堆有 𝑎 𝑖 个,因为羊驼 Luck 就要毕业了,所以她想
要摧毁所有的积木。Luck 有一个法杖,每次 Luck 挥动法杖的时候,可以摧毁连续的一排或
者连续的一列积木,连续指的是同一排或者同一列不能有空缺。
例如:现有 5 堆积木,每堆积木中分别有 2,2,1,2,1 块积木,当 Luck 摧毁第二排积木的
时候,需要挥动两次法杖。
现在问 Luck 最少挥动几次法杖可以把所有积木都摧毁。

输入格式
第一行一个正整数 n(1≤n≤5000) 表示有 n 堆积木。
第二行 n 个整数 𝑎 𝑖 (1≤ 𝑎 𝑖 10 9 ),表示每堆中有多少个积木。
输出格式:
一个整数,表示 Luck 摧毁所有积木,最少挥动的法杖次数。
输入样例 1:
5
2 2 1 2 1
输出样例 1:
3
输入样例 2:
7
10 2 3 1 8 12 4
输出样例 2:
7
Java实现:
public static int time=0;
public static int destroy(int begin, int end, int[] col) {
int n = end - begin;// 数组长度
int max_i = max(begin, end, col);
int min_i = min(begin, end, col);
if(col[max_i]==0 || begin>=end) {
return 0;
}
// 当某一竖行的方块最多时
if (col[max_i] > n) {
col[max_i] = 0;//破坏该列的积木
time++;
if(begin<max_i)
destroy(begin, max_i, col);
if(max_i+1<end)
destroy(max_i+1, end, col);
}else if(col[min_i] == 0 ) {//积木出现间隔,从间隔处分而治之
if(begin<min_i)
destroy(begin, min_i, col);
if(min_i+1<end)
destroy(min_i+1, end, col);
}
else{//此时最下面一行的积木最多,破坏最下面一行的积木
for (int i = begin; i < end; i++) {
col[i] -= 1;
}
for(int i=0;i<col.length;i++)
System.out.print("$"+ col[max_i]);
System.out.println();
time++;
destroy(begin, end, col);
}
return time;
}
 

python实现:

import numpy as np
import pandas as pd

destroy_n = 0

n = int(input('请输入积木的堆数:'))
a_i = [int(i) for i in input('请输出每堆有多少积木(空格分割):').split(' ')]


# 生成积木
def gen_block(n, a_i):
    block_heap = pd.DataFrame(np.zeros((max(a_i), n)))
    for i in range(n):
        block_heap.iloc[:a_i[i], i] = 1
    print(block_heap)
    return block_heap


# 统计行的最大积木数量
def statistic_raw_max(block_heap):
    raw_max = 0
    max_coordinates = []

    for raw in range(block_heap.shape[0]):
        raw_max_temp = 0
        raw_max_blocks = []
        raw_max_coordinates = []
        for col in range(block_heap.shape[1]):
            if block_heap.iloc[raw, col] == 1:
                raw_max_temp += 1
                raw_max_coordinates.append([raw, col])
            else:
                raw_max_blocks.append(raw_max_temp)
                if raw_max_blocks:
                    if raw_max < max(raw_max_blocks):
                        raw_max = raw_max_temp
                        max_coordinates = raw_max_coordinates
                    elif raw_max > max(raw_max_blocks):
                        pass
                    # 如果在后续的统计中,两个最大值相同,坐标不再更新,以先出现最大值的坐标为先
                    else:
                        pass
                raw_max_blocks.append(raw_max_temp)
                raw_max_temp = 0
                raw_max_coordinates = []

        # 这种情况是一行全是1
        if raw_max_temp == block_heap.shape[1]:
            raw_max = raw_max_temp
            max_coordinates = raw_max_coordinates

    return raw_max, max_coordinates


# 统计列的最大积木数量
def statistic_column_max(block_heap):
    col_max = 0
    max_coordinates = []
    for col in range(block_heap.shape[1]):
        col_max_temp = 0
        col_max_blocks = []
        col_max_coordinates = []
        for raw in range(block_heap.shape[0]):
            if block_heap.iloc[raw, col] == 1:
                col_max_temp += 1
                col_max_coordinates.append([raw, col])
            else:
                col_max_blocks.append(col_max_temp)
                if col_max < max(col_max_blocks):
                    col_max = col_max_temp
                    max_coordinates = col_max_coordinates
                elif col_max > max(col_max_blocks):
                    pass
                # 如果在后续的统计中,两个最大值相同,坐标不再更新,以先出现最大值的坐标为先
                else:
                    pass
                col_max_blocks.append(col_max_temp)
                col_max_temp = 0
                col_max_coordinates = []

        # 这种情况是一列全部是1
        if col_max_temp == block_heap.shape[0]:
            col_max = col_max_temp
            max_coordinates = col_max_coordinates

    return col_max, max_coordinates


# 递归的破坏积木堆,每次破坏只破坏最大积木数量的行或列
def destroy_block_heap(block_heap):
    global destroy_n
    raw_max, raw_coordinates = statistic_raw_max(block_heap)
    col_max, col_coordinates = statistic_column_max(block_heap)
    if raw_max == 0 and col_max == 0:
        return
    if raw_max > col_max:
        destroy_n += 1
        print(f'第{destroy_n}次破坏: 破坏数量{raw_max}, 破坏的坐标{raw_coordinates}')
        for coor in raw_coordinates:
            block_heap.iloc[coor[0], coor[1]] = 0
        print(block_heap)
        destroy_block_heap(block_heap)
    elif raw_max < col_max:
        destroy_n += 1
        print(f'第{destroy_n}次破坏: 破坏数量{col_max}, 破坏的坐标{col_coordinates}')
        for coor in col_coordinates:
            block_heap.iloc[coor[0], coor[1]] = 0
        print(block_heap)
        destroy_block_heap(block_heap)
    else:
        destroy_n += 1
        print(f'第{destroy_n}次破坏: 破坏数量{raw_max}, 破坏的坐标{raw_coordinates}')
        for coor in raw_coordinates:
            block_heap.iloc[coor[0], coor[1]] = 0
        print(block_heap)
        destroy_block_heap(block_heap)


block_heap = gen_block(n, a_i)
destroy_block_heap(block_heap)
print(f'最少需要挥动法杖{destroy_n}次')

C++实现

#include <iostream>
#include <algorithm>
#include <stack>
#include<iostream>
using namespace std;
int knife;        //切了多少刀
int stack_number; //一共有几堆积木
int max_H_stack;  //最大横堆有多少个积木
int arr[100]; //每堆积木多少个
int max = 0; // 最大值
int y;
int z;//发生替换的位置
int Max(int arr[]) 
{
    int max=0;// 最大值

    for (int i = 0; i < stack_number;i++) {
        if (arr[i] > max) { // 当前值大于最大值,赋值为最大值
            max = arr[i];
            y = i;
        }
    }
    return max;
}
int look_h_max(int arr[]) 
{
    max_H_stack = 0;
    int temp=0;
    for (int i = 0; i < stack_number; i++) {
        if (arr[i] >0) {
            temp = temp + 1;
            if (temp >= max_H_stack)
            {
                max_H_stack = temp;
                z = i;
            }
        }
        else {
            temp = 0;
        }
    }
    return max_H_stack;
}
int calculate_knife(int arr[], int stack_number)
{
    bool flag=true;
    int temp = 0;
    while(temp!= stack_number)
    //for(int i=0;i<=10;i++)
    {
       
        if (Max(arr) > look_h_max(arr))
        {
           
            //cout << "纵切:" << Max(arr);
            arr[y] = 0;

        }
        else
        {
            //cout << "横切:" << max_H_stack;
            for (int i = z; i >=0; i--)
            {
                if (arr[i] > 0) {
                    arr[i] = arr[i] - 1;
                }
                else {
                    break;
                }
            }
        }
        knife = knife + 1;
        temp = 0;
        for (int i = 0; i < stack_number; i++)
        {
            if (arr[i] <= 0) {
                temp++;
            }
        }
        
    }
    return knife;
}
int main()
{
    cin >> stack_number;
    for (int i = 0; i < stack_number; i++) {
        cin >> arr[i];
    }
    
    calculate_knife(arr, stack_number);
   
    cout << knife; 
    return 0; 
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值