削减木板的最低成本

时间:2014-02-23 17:24:32

标签: algorithm

鉴于木板由M X N木制方块组成,我们需要找到将木板打成方形木块的最低成本。

我们可以沿水平和垂直线切割电路板,每次切割将电路板分成较小的部分。每块板的切割成本取决于切割是沿水平线还是垂直线进行。

让我们用沿x [1],x [2],...,x [n-1]的连续垂直线和y [1],y [2],...的水平线切割它的成本。 ,y [m-1]。如果削减(成本c)并且它通过n个段,那么这个削减的总成本将为n * c。

将整块板切割成单个正方形的成本是用于将整个板切割成尺寸为1x1的方形木块的连续切割成本的总和。

将整个木板分成1x1大小的最小成本是什么。

示例:我们采取6 * 4网格。

让沿着行划分成本如下:[2 1 3 1 4]

按照以下方式削减柱成本:[4 1 2]

这里的答案是42

我们应该按顺序使用y5,x1,y3,y1,x3,y2,y4和x2开始切割。第一次切割将是水平的,其中cost = y5 = 4.接下来我们将使用x1进行垂直切割。由于此切割通过两个段(由先前的垂直切割创建),因此总成本将为2 * x1 = 2 * 4。类似地,下一个水平切割(y3)将通过两个段并且将花费2 * y3 = 2 * 3。我们可以采取类似的方式进行,总成本为4 + 4 * 2 + 3 * 2 + 2 * 2 + 2 * 4 + 1 * 3 + 1 * 3 + 1 * 6 = 42。

我的方法:检查从第1行和第2行之间的切割开始的每次切割,然后等等。但显然效率太低。那么如何解决这个问题呢?

6 个答案:

答案 0 :(得分:18)

分割线的选择应按递减的成本顺序进行,以实现最低的总成本。

<强>证明:

任何“错误”排序的切割序列必须具有2个连续切割C1和C2,其成本为c1和c2,使得c1

另一方面,如果C1是垂直的而C2是水平的(不失一般性),那么我们可以如下检查它。设V0为施加C1之前的垂直片段数,H0为C1之前的水平片段数。

  • 应用C1然后C2的成本是:H0 * c1 +(V0 + 1)* c2
  • 应用C2然后C1的成本为:V0 * c2 +(H0 + 1)* c1

第一个表达式减去第二个表达式给出了c2-c1,它是正的。换句话说,交换C1和C2可以降低成本。

结论:使用一系列交换,任何非有序序列都可以转换为有序序列,这样总成本只能降低。这样就完成了最优性证明。

注意:如果多次削减成本相同,其内部订购根本不会影响总成本,如上面的计算所示。

答案 1 :(得分:3)

这个问题可以通过贪婪算法来解决。

仅有1条规则: - 按递减顺序选择切割成本,如果两个或更多成本相等,请选择任意一个。 这是python解决方案: -

M, N = map(int, raw_input().strip().split(' '))
Y = map(int, raw_input().strip().split(' '))
X = map(int, raw_input().strip().split(' '))

Y.sort(reverse=True)
X.sort(reverse=True)

y_cut = x_cut = 1     #To count the number of segments
cost = i = j = 0

while i < X.__len__() and j < Y.__len__():
    if X[i] >= Y[j]:
        x_cut = x_cut + 1
        cost = cost + (X[i]*y_cut)
        i = i+1
    else:
        y_cut = y_cut + 1
        cost = cost + (Y[j]*x_cut)
        j = j+1

while i < X.__len__():
    cost = cost + (X[i]*y_cut)
    i = i+1

while j < Y.__len__():
    cost = cost + (Y[j]*x_cut)
    j = j+1

print cost

答案 2 :(得分:1)

虽然问题已经得到解答,但我写这篇文章是为了提供一个非正式的,可能是直观的解释:

我们必须进行(n-1)*(m-1)次切割,所以我们只需要决定首先选择哪种切割。

让我们说我们必须在成本c1和c2的两个削减C1和C2之间进行选择。我们说c1> c2。让整个事件的总电流成本用C

表示

如果我们在此步骤之后选择C1,它将至少添加(取决于您是否在下一步中添加它)c1到整个成本,C。 如果我们在这个步骤之后选择C2,它将至少将c2添加到整个成本,C。

所以我们可以说我们现在可以贪婪地选择C1,因为以后选择它会比以后选择C2更糟糕。

因此,我们选择降低成本的顺序,而不管切割的类型(水平,垂直)。

答案 3 :(得分:0)

只需选择降低成本的切割线,这里是c ++中的代码

代码:

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

int main() {
long int t;
cin >> t;
while(t--){
    long long int m,n,*x,*y,i,j,sum,cx,cy,modu = 1000000007;
    cin >> m >> n;
    x = new long long int[m-1];
    y = new long long int[n-1];
    for(i=0;i<m-1;i++)
    cin >> x[i];
    for(i=0;i<n-1;i++)
    cin >> y[i];
    sort(y,y+n-1);
    sort(x,x+m-1);

    i=m-1-1;sum=0;j=n-1-1;cx = 1;cy =1;
    while(i>=0 && j >=0){

         if(x[i] > y[j]){
            sum += (x[i]*cy)%modu;
            cx++;
            i--;
        }
        else{
            sum += (y[j]*cx)%modu;
            cy++;
            j--;
        }
    }

    while(i>=0){
        sum += (x[i]*cy)%modu;
        i--;
    }
    while(j>=0){
        sum += (y[j]*cx)%modu;
        j--;
    }

    cout << sum%modu << endl;
}
return 0;
}

答案 4 :(得分:0)

这是我在Python 2中的贪婪算法。

  1. 为了最大限度地降低成本,必须首先削减最昂贵的地点
  2. 切割次数为(M-1)+(N-1)
  3. 内部秩序无关紧要。因为最终所有的地点都将被削减
  4. 跟踪每个维度(nx,ny)的当前切割数量
  5. <强>代码

    M,N = [int(x) for x in raw_input().split()]
    CY = sorted([int(x) for x in raw_input().split()], reverse=True)
    CX = sorted([int(x) for x in raw_input().split()], reverse=True)
    nx = 1
    ny = 1
    minC = 0
    i = 0
    j = 0
    total = M - 1 + N - 1
    for _ in range(0,total):
        #j == N - 1 to check if CX is exhausted
        if (j == N - 1 or (i != M -1 and CY[i] > CX[j])):
            minC += CY[i]*nx
            ny += 1
            i += 1
        else:
            minC += CX[j]*ny
            nx += 1
            j += 1
    
    print minC%(1000000000+7)
    

答案 5 :(得分:-2)

嗯,这似乎很简单。因此,您需要进行所有削减并最大限度地减少最昂贵的削减数量,您只需按成本订购即可。

虽然有一个问题 - 如果您的削减价格相同,那么您需要对它们进行分组。假设您必须进行5次切割,每种价格为6,列数为4,行数为2,未切割。如果您先裁减2行,则费用为2 * 6 + 4 * 3 * 6 = 14 * 6。如果您以其他方式执行此操作,则会获得4 * 6 + 2 * 4 * 6 = 12 * 6

规则首先是高价切割,首先沿轴线进行大多数切割。

编辑:要跟踪您拥有的细分数量,您需要跟踪对其他轴进行的剪切。 o如果您对行进行了3切割,则切割列将需要3 + 1次切割。如果您已经剪切了5列和3行,则切割另一行将始终必须遍历每个列切割行,这意味着您必须剪切5 + 1次。

编辑2:由于我的示例不正确,这就是使用来自问题的情况的样子:

cut_x = [2, 1, 3, 1, 4]
cut_y = [4, 1, 2]

list_of_cuts_grouped_by_cost_descending = [[x5, y1], [x3], [x1, y3], [x2, y2, x4]]

cut_groups_ordered_by_most_cut_axis = [[x5, y1], [x3], [x1, y3], [x2, x4, y2]]

return cut_groups_ordered_by_most_cut_axis.flatten