Python棒切割算法 - 变体

时间:2013-02-05 02:09:24

标签: python algorithm dynamic-programming

在我的一个课程中,我被问到这是一个脑筋急转弯,但却无法弄清楚(不是一个家庭作业问题,只是TA的一个预告片让我们思考)。

你会得到一个带有n个切点列表的杆,例如[1,5,11],以及杆的总长度,例如20.你也被告知切割的费用。杆相当于杆的长度。我们希望找到在所有给定切割时切割杆的最低成本以及这些切割的顺序,这将导致最佳成本。

例如,要在第5位切割长度为20的杆,它将花费20美元,最终会有2个原木,一个长度为5,另一个长度为15。

或者在另一个例子中,如果你在第5个位置然后在第10个位置切割长度为25的杆,那么在第5个位置切割它需要花费25美元,留下长度为5的杆和长度为20的杆,然后再花20美元将它削减到第10位,给你两个位置削减45美元的总成本。但是如果你在第10位然后在第5位切割杆,则需要花费25美元+ 10美元= 35美元。

最后,我们想要return the minimum cost of cutting the rod at all the given cuts and the sequence of those cuts that would lead to the optimal cost.

我试图为这个问题提出一个递归的解决方案,但是一直空手而归。思考?任何帮助表示赞赏。谢谢!

2 个答案:

答案 0 :(得分:1)

我认为棒切割问题的关键在于贪婪算法并不总能产生最佳解决方案 - 这种变体似乎证明了相同的观点。

考虑在[13,25,26]处切割的L = 50杆。选择最接近中点的剪切的算法会告诉您执行[25, 13, 26],总费用为50 + 25 + 25 = 100。我们可以通过[26, 13, 25]进行改进,总费用为50 + 26 + 13 = 89

修改

即。你会在L=50切出一根P=26杆,导致L=24 (P=26->50)杆不再需要切割,而L=26 (P=0->26)杆需要在[25,13]切割。然后你在L=26切割P=13杆,导致一根L=13 (P=0->13)杆不再需要切割,另一根L=13 (P=13->26)杆需要在P=25进行最终切割。然后进行最终切割,得到的成本是每个阶段切割的杆长度之和(50 + 26 + 13)。

通常提出的替代方案是自上而下和自下而上的技术,这些技术的效率通常取决于所涉及的逻辑(对于您试图最大化销售成本的传统切杆问题,自下而上是首选它减少了递归调用。)

答案 1 :(得分:0)

为了解决这个问题,您必须使用动态编程方法。这是一个基于O(n ^ 3)的解决方案。(如果有人有更好的解决方案请评论)。让我们得到一个数组a [n + 1] [n + 1],其中n =杆的长度。 a [i] [j]将存储从位置i切割到位置j的最小成本。我们给出了一个切割阵列,其中包含切割杆的所有位置。对于每个i-j杆,我们考虑将切割阵列中给出的所有k个位置切割下来并找出最小成本。我们以对角线方式填充阵列。 (评论如果需要更多解释)

#include <iostream>
#include <string.h>
#include <stdio.h>  
#include <limits.h>
using namespace std;
int main(){
   int i,j,gap,k,l,m,n;
   while(scanf("%d%d",&n,&k)!=EOF){

    int a[n+1][n+1];
    int cut[k];
    memset(a,0,sizeof(a));
    for(i=0;i<k;i++)
        cin >> cut[i];
    for(gap=1;gap<=n;gap++){
        for(i=0,j=i+gap;j<=n;j++,i++){
            if(gap==1)
                a[i][j]=0;
            else{
                int min = INT_MAX;
                for(m=0;m<k;m++){
                    if(cut[m]<j and cut[m] >i){
                        int cost=(j-i)+a[i][cut[m]]+a[cut[m]][j];

                        if(cost<min)
                            min=cost;
                    }
                }
                if(min>=INT_MAX)
                a[i][j]=0;
                else
                    a[i][j]=min;
            }
        }
    }
    cout << a[0][n] << endl;
}
return 0;
}