用c++语言完成以下题目:蒜头君要进行小屋装修改造,现在他有 n 块木料,第 i 块木料的高度为 2^{ai} 。蒜头君可以对木料进行若干次操作,直到无法操作为止: 选择两块相邻且高度相同的木料,将两块木料钉到一起,形成一块儿更高的木料,高度为两块木料的高度之和。 现在蒜头君想要知道:他最少可能进行多少次操作。
时间: 2023-05-25 14:06:59 浏览: 31
思路:贪心+优先队列
首先考虑贪心思想,如果两块相邻且高度相同的木料不相邻,肯定不是最优的选择。因此,我们可以想到使用贪心算法,每次找到最长的相同高度的木料连成一块,然后合并。
但是,这个合并的过程可能会影响到其他的木料,因此需要重新运用贪心的思想,选择最小的影响,然后再合并。
为了方便找到最长的相同高度的木料,我们可以使用一个优先队列,将所有木料的高度放入其中,每次取出前两个相等的,合并它们,并将新的高度放回队列中。
具体实现如下:
相关问题
用c++语言完成以下题目:蒜头君要进行小屋装修改造,现在他有 n 块木料,第 i 块木料的高度为 2^{ai} 。蒜头君可以对木料进行若干次操作,直到无法操作为止: 选择两块相邻且高度相同的木料,将两块木料钉到一起,形成一块儿更高的木料,高度为两块木料的高度之和。 现在蒜头君想要知道:他最少可能进行多少次操作。
思路:
我们可以用 greedy 的思路,每次将相邻两块高度最近似的木料合并,从而减少操作次数。
具体方法是将所有木料按高度从小到大排好序,并将原始高度转换为对数形式。即对于第 i 块木料,将其高度 a[i] 转换为 log2(a[i])。
然后我们从小到大遍历木料,每次找出相邻的两块木料中高度最近似的两个并合并。
我们可以用堆来维护每次遍历到某一块木料时,高度最近似的两块木料。具体来说,对于第 i 块木料,我们从堆中弹出最小的那个数,即它的左侧或右侧的高度最近似的木料,然后与第 i 块木料合并。
由于每个木料只会被合并一次,因此操作次数不会超过 n。
代码实现:
本题是一道比较模板化的贪心题,代码实现相对简单。
用c++语言的代码完成以下题目:蒜头君要进行小屋装修改造,现在他有 n 块木料,第 i 块木料的高度为 2^{ai} 。蒜头君可以对木料进行若干次操作,直到无法操作为止: 选择两块相邻且高度相同的木料,将两块木料钉到一起,形成一块儿更高的木料,高度为两块木料的高度之和。 现在蒜头君想要知道:他最少可能进行多少次操作。
思路:由于两块高度相同的木料才可以进行操作,所以我们要找到所有相同高度的木料并进行聚合,直到最终只剩下一块木料为止。因此,我们可以使用一个 map 来记录每种高度的木料的数量,然后从小到大不断找相邻两个高度相同的木料进行聚合,直到只剩下一块木料为止。
代码实现:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>
#include <string.h>
#define MAXN 100000
int n, a[MAXN + 5];
int cnt[MAXN * 2 + 5];
int main() {
scanf("%d", &n);
for (int i = 1;i <= n;i++) {
scanf("%d", &a[i]);
cnt[a[i]]++;
}
int ans = 0;
bool flag = true;
while (flag) {
flag = false;
for (int i = 0;i <= 20;i++) {
if (cnt[i] >= 2) {
int t = cnt[i] / 2;
cnt[i + 1] += t;
cnt[i] -= t * 2;
ans += t;
flag = true;
}
}
}
printf("%d\n", ans);
return 0;
}