积木城堡

该问题是一个关于使用动态规划(DP)策略的编程题目。目标是帮助小XC改造他的积木城堡,使其每个城堡的高度相同且尽可能高。输入包含多座城堡的积木信息,输出是城堡的最大可能统一高度。通过动态规划的状态转移方程计算,找到可行的积木组合方案。
摘要由CSDN通过智能技术生成

题目描述

XC 的儿子小 XC 最喜欢玩的游戏用积木垒漂亮的城堡。城堡是用一些立方体的积木垒成的,城堡的每一层是一块积木。

小 XC 是一个比他爸爸 XC 还聪明的孩子,他发现垒城堡的时候,如果下面的积木比上面的积木大,那么城堡便不容易倒。所以他在垒城堡的时候总是遵循这样的规则。

小 XC 想把自己垒的城堡送给幼儿园里漂亮的女孩子们,这样可以增加他的好感度。为了公平起见,他决定把送给每个女孩子一样高的城堡,这样可以避免女孩子们为了获得更漂亮的城堡而引起争执。

可是他发现自己在垒城堡的时候并没有预先考虑到这一点。所以他现在要改造城堡。由于他没有多余的积木了,他灵机一动,想出了一个巧妙的改造方案。他决定从每一个城堡中挪去一些积木,使得最终每座城堡都一样高。为了使他的城堡更雄伟,他觉得应该使最后的城堡都尽可能的高。

任务:

请你帮助小 XC 编一个程序,根据他垒的所有城堡的信息,决定应该移去哪些积木才能获得最佳的效果。

注意:一座城堡的高度,是组成它的所有积木的棱长之和。

输入格式

第一行是一个整数 nn,表示一共有 nn 座城堡。

以下 nn 行每行是一系列非负整数,用一个空格分隔,按从下往上的顺序依次给出一座城堡中所有积木的棱长。用 -1 结束。

输出格式

一个整数,表示最后城堡的最大可能的高度。
如果找不到合适的方案,则输出 00。

输入输出样例

输入 #1复制

2
2 1 -1
3 2 1 -1

输出 #1复制

3

说明/提示

【数据范围】
对于 100\%100% 的数据,1 \le n \le 1001≤n≤100,一座城堡中的积木不超过 100100 块,每块积木的棱长不超过 100100

这道题可以用DPDP(动态规划)来做~

DP必备三步:

  • 状态表示状态表示
  • 动态转移动态转移
  • 初始状态初始状态

开始吧!~~~~~     我们可以先只考虑单独城堡~k~ k ~~


First~~状态表示First  状态表示

  • dp[i][j]~dp[i][j] 表示用前~i~ i 块积木能否达到高度~j~ j 

Next ~~动态转移Next  动态转移

  • 不选第~i~ i 块积木 dp[i][j] = dp[i-1][j]dp[i][j]=dp[i−1][j]

  • 选第~i~ i 块积木 dp[i][j] = dp[i-1][j-w[i]]dp[i][j]=dp[i−1][j−w[i]]

倒叙降维,用~|=~ ∣= 连接~~  得:

  • dp[j] ~~|= ~~dp[j-w[i]]dp[j]  ∣=  dp[j−w[i]]

Last ~~初始状态Last  初始状态

很简单~

不搭积木肯定行呀!

  • dp[0] = 1dp[0]=1

用代码呈现~

#include <bits/stdc++.h> //万能头
using namespace std;

int n,len,min_high = 2e9,w[105],ans[10005];
// w数组为每一城堡积木的高度 ans数组为达到高度i的个数
bool dp[10005];
// Dp嘛
int main() {
    cin >> n; //n个城堡
    for(int k=1;k<=n;k++)// 每一个城堡
    {
        //memset(w,0,sizeof(w)); // 其实不用
        memset(dp,0,sizeof(dp)); // 以免前一个影响当前城堡
        int cnt = 0,high = 0; //cnt为积木个数,high为高度~
        while(1)
        {
            cin >> len; //输入len
            if(len == -1) break; // 输入完了~
            w[++cnt] = len; // 存高度~
            high += len; // 算高度~
        }
        // 开始DP!
        dp[0] = 1; // 初始状态
        for(int i=1;i<=cnt;i++)// 物品维(cnt个积木)
            for(int j=high;j>=w[i];j--)// 容量~倒叙枚举压物品维 枚举到物品大小
                dp[j] |= dp[j-w[i]]; //动态转移方程
        min_high = min(min_high,high); // 最小值~
        for(int i = high;i>=1;i--) // 检查一下能否达到高度
            if(dp[i] == 1) ans[i]++;// 加到ans数组~
    }
    for(int i = min_high;i>=1;i--)// 看看那个高度可以所有达到!
        if(ans[i] == n)
        {
            cout << i;// 输出
            return 0;
        }
    cout << "0";//没有,输出0
    return 0;
}

PS:代码两重循环,看范围,不会TLETLE的~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值