Java 在给定约束的最小移动中,将数组减少为0
您将看到一个位于x轴上的城市。它有n座建筑物。第一座建筑位于x=1,高度为h1,第二座建筑位于x=2,高度为h2,依此类推。你是一个拿着剑的巨大怪物,想要摧毁这座城市。你的内心也是一名计算机科学家,所以你的效率是关键,因此你想用最少的移动次数来摧毁这座城市 您可以执行以下两个动作之一: 1。从x=L到x=R进行水平切割,将建筑物的高度从x=L到x=R减少1。 2。在x=P处进行垂直切割,在x=P处完全破坏建筑物,从而使其高度为零。** 注意:对于第一种移动,从L到R范围内的每个城市必须至少有一个剩余高度,即不能穿过空白区域。 打印摧毁城市所需的最少移动次数 输入 第一行包含测试用例的数量。 对于每个测试用例,第一行包含建筑物的数量n。 第二行包含n个整数,表示建筑物的高度 输出 对于每个测试用例,在新行上打印摧毁城市的最小移动次数 注释 一,≤ N≤ 1000 0≤ 你好≤ 一千 样本输入0 二, 五, 2 2 3 3 五, 10210210 样本输出0 三, 五, 我想不出解决这个问题的方法。 我的代码不适用于以下输入: 1 1 1 2 4 5 7 7 8 9** 在我的代码中,我减少了所有元素的最小值。然后找出零之间的子阵,然后将子阵长度(j-i)与最小值进行比较。如果长度小于,那么我们需要跟随移动2,否则移动1。 我的代码:Java 在给定约束的最小移动中,将数组减少为0,java,algorithm,data-structures,dynamic-programming,divide-and-conquer,Java,Algorithm,Data Structures,Dynamic Programming,Divide And Conquer,您将看到一个位于x轴上的城市。它有n座建筑物。第一座建筑位于x=1,高度为h1,第二座建筑位于x=2,高度为h2,依此类推。你是一个拿着剑的巨大怪物,想要摧毁这座城市。你的内心也是一名计算机科学家,所以你的效率是关键,因此你想用最少的移动次数来摧毁这座城市 您可以执行以下两个动作之一: 1。从x=L到x=R进行水平切割,将建筑物的高度从x=L到x=R减少1。 2。在x=P处进行垂直切割,在x=P处完全破坏建筑物,从而使其高度为零。** 注意:对于第一种移动,从L到R范围内的每个城市必须至少有一个
import java.util.ArrayList;
导入java.util.array;
导入java.util.List;
导入java.util.stream.collector;
导入java.util.stream.IntStream;
导入java.util.Scanner;
公共班机{
静态int findmin(int arr[],int i,int j){
int min=整数最大值;
对于(int k=i;karr[k]){
最小值=arr[k];
}
}
返回最小值;
}
静态空差最小值(int arr[],int i,int j,int min){
//如果子阵的长度和最小值相等,我们将分别销毁
if(j-i输入[i]){
min=输入[i];
}
如果(输入[i]==0){
零++;
}
}
//从数组中减去最小元素
整数计数=0;
如果(零=0){
计数+=分钟;
减法最小值(输入,0,n,最小值);
}否则{
计数+=分钟;
减法最小值(输入,0,n,最小值);
}
//在0之间遍历数组和FindSubArray
//1) 如果一个元素被0包围,它将立即被单独销毁
//2)同样,如果子阵列的长度这里一个可能的提示是,将建筑减少到零会分隔部分,这意味着分而治之
让f(A,l,r)
表示A
段在[l,r]
处索引的最佳移动次数。然后:
f(A, l, r):
min(
# Reduce the whole section
# without separating it, using
# move 1, the horizontal cuts.
max(A[l..r]),
# Divide and conquer
1 + f(A, l, k-1) + f(A, k+1, r)
)
for all l ≤ k ≤ r
除了我们不需要尝试所有k
s外,只需指向max(A)
的一个。不删除max(A)
意味着我们需要执行max(A)
移动,或者我们以后必须删除它
JavaScript代码:
函数findMax(A、l、r){
设idx=l;
for(设i=l;ia[idx])
idx=i;
返回idx;
}
函数f(A,l=0,r=A.length-1,memo={}){
如果(l>r)
返回0;
如果(l==r)
返回1;
常量键=字符串([l,r]);
if(备注hasOwnProperty(键))
返回备忘录[键];
常数k=findMax(A,l,r);
const best=Math.min(A[k],1+f(A,l,k-1,memo)+f(A,k+1,r,memo));
返回备忘录[键]=最佳;
}
变量As=[
[2, 2, 2, 3, 3],
[10, 2, 10, 2, 10],
[1, 1, 1, 2, 4, 5, 7, 7, 8, 9]
];
例如
console.log(f(A));
您遇到的问题不在代码中,而在算法中。如果段的大小足够小,则必须有效地执行move 2。但是,此条件不是必不可少的
实际上,简单的递归方法可以解决这个问题。在给定的段[k,l]中,减去最小值后,您只需执行以下操作:
n_moves = min (n, vmin + min_moves(x, k, l));
在下面,一个函数检测零的位置,并将对应于每个段的移动相加
为每个段调用另一个函数,内部没有零
下面的代码是C++的,但是它相当简单,应该很容易翻译成另一种语言。
输出:
1 2 7 : 3
2 2 2 3 3 : 3
10 2 10 2 10 : 5
1 1 1 2 4 5 7 7 8 9 : 8
提供此代码是为了完整性。重要的是算法本身
#include <iostream>
#include <vector>
#include <algorithm>
std::vector<int> get_zeros (const std::vector<int> &x, int k, int l) {
std::vector<int> zeros;
for (int i = k; i <= l; ++i) {
if (x[i] == 0) zeros.push_back(i);
}
return zeros;
}
int min_moves (std::vector<int> &x, int k, int l);
// This function is called after detection the position of the zeros -> no zero inside
int min_moves_no_zero (std::vector<int> &x, int k, int l) {
int n = l-k+1;
if (n == 0) return 0;
if (n == 1) return 1;
int vmin = 10000;
for (int i = k; i <= l; ++i) {
if (x[i] < vmin) vmin = x[i];
}
for (int i = k; i <= l; ++i) {
x[i] -= vmin;
}
int nm = std::min (n, vmin + min_moves(x, k, l));
return nm;
}
// This function detects positions of the zeros and sum the moves corresponding to each segment
int min_moves (std::vector<int> &x, int k, int l) {
auto zeros = get_zeros (x, k, l);
if (zeros.size() == 0) return min_moves_no_zero (x, k, l);
int start = k;
int total = 0;
for (int z = 0; z < zeros.size(); ++z) {
int end = zeros[z] - 1;
if (start != zeros[z]) {
total += min_moves_no_zero (x, start, end);
}
start = end + 2;
}
if (start <= l) {
total += min_moves_no_zero (x, start, l);
}
return total;
}
void print (const std::vector<int> &x) {
for (auto k: x) {
std::cout << k << " ";
}
}
int main() {
std::vector<std::vector<int>> input {
{1, 2, 7},
{2, 2, 2, 3, 3},
{10, 2, 10, 2, 10},
{1, 1, 1, 2, 4, 5, 7, 7, 8, 9}
};
for (auto& arr: input) {
auto save = arr;
int moves = min_moves (arr, 0, arr.size()-1);
print (save);
std::cout << " : " << moves << "\n";
}
}
#包括
#包括
#包括
std::vector get_zero(const std::vector&x,int k,int l){
std::向量零;
对于(int i=k;i内部无零
整数最小值移动零(标准::向量&x,整数k,整数l){
int n=l-k+1;
如果(n==0)返回0;
如果(n==1)返回1;
int-vmin=10000;
对于(int i=k;i这与java或python有什么关系?:)嘿!请发布你的代码。我发布了我的代码。你提到你的代码不适用于此输入。输出是什么?预期输出是什么?我的输出是9。预期输出是8。请注意,OP要求的是java
,而不是Javascript
(编辑后)。
#include <iostream>
#include <vector>
#include <algorithm>
std::vector<int> get_zeros (const std::vector<int> &x, int k, int l) {
std::vector<int> zeros;
for (int i = k; i <= l; ++i) {
if (x[i] == 0) zeros.push_back(i);
}
return zeros;
}
int min_moves (std::vector<int> &x, int k, int l);
// This function is called after detection the position of the zeros -> no zero inside
int min_moves_no_zero (std::vector<int> &x, int k, int l) {
int n = l-k+1;
if (n == 0) return 0;
if (n == 1) return 1;
int vmin = 10000;
for (int i = k; i <= l; ++i) {
if (x[i] < vmin) vmin = x[i];
}
for (int i = k; i <= l; ++i) {
x[i] -= vmin;
}
int nm = std::min (n, vmin + min_moves(x, k, l));
return nm;
}
// This function detects positions of the zeros and sum the moves corresponding to each segment
int min_moves (std::vector<int> &x, int k, int l) {
auto zeros = get_zeros (x, k, l);
if (zeros.size() == 0) return min_moves_no_zero (x, k, l);
int start = k;
int total = 0;
for (int z = 0; z < zeros.size(); ++z) {
int end = zeros[z] - 1;
if (start != zeros[z]) {
total += min_moves_no_zero (x, start, end);
}
start = end + 2;
}
if (start <= l) {
total += min_moves_no_zero (x, start, l);
}
return total;
}
void print (const std::vector<int> &x) {
for (auto k: x) {
std::cout << k << " ";
}
}
int main() {
std::vector<std::vector<int>> input {
{1, 2, 7},
{2, 2, 2, 3, 3},
{10, 2, 10, 2, 10},
{1, 1, 1, 2, 4, 5, 7, 7, 8, 9}
};
for (auto& arr: input) {
auto save = arr;
int moves = min_moves (arr, 0, arr.size()-1);
print (save);
std::cout << " : " << moves << "\n";
}
}