java – 使用动态编程复制书籍

我正在实施动态编程解决方案来复制书籍问题.解决方案的想法来自
here
here.

问题陈述:

Before the invention of book-printing, it was very hard to make a copy
of a book. All the contents had to be re-written by hand by so called
scribers. The scriber had been given a book and after several months
he finished its copy. One of the most famous scribers lived in the
15th century and his name was Xaverius Endricus Remius Ontius
Xendrianus (Xerox). Anyway, the work was very annoying and boring. And
the only way to speed it up was to hire more scribers.

Once upon a time, there was a theater ensemble that wanted to play
famous Antique Tragedies. The scripts of these plays were divided into
many books and actors needed more copies of them, of course. So they
hired many scribers to make copies of these books. Imagine you have m
books (numbered 1, 2, …., m) that may have different number of pages
( p_1, p_2, …, p_m) and you want to make one copy of each of them.
Your task is to divide these books among k scribes, k <= m. Each book
can be assigned to a single scriber only, and every scriber must get a
continuous sequence of books. That means, there exists an increasing
succession of numbers 0 = b_0 < b_1 < b_2, … < b_{k-1} <= b_k = m$
such that i-th scriber gets a sequence of books with numbers between
bi-1+1 and bi. The time needed to make a copy of all the books is
determined by the scriber who was assigned the most work. Therefore,
our goal is to minimize the maximum number of pages assigned to a
single scriber. Your task is to find the optimal assignment.

我能够迭代地获得所描述问题的最佳解决方案,但无法使用它来找到问题所需的解决方案,即:

Sample input:
2
9 3
100 200 300 400 500 600 700 800 900
5 4
100 100 100 100 100

Sample Output
100 200 300 400 500 / 600 700 / 800 900
100 / 100 / 100 / 100 100

其中2是数据集的数量,9是书籍数量,3是分配书籍的抄写员数量.

以下是我输出的相应输入:

100 100 100 
300 300 300 
600 600 600 
1000 700 700 
1500 900 900 
2100 1100 1100 
2800 1300 1300 
3600 1500 1500 
4500 1700 1700 

100 100 100 100 
200 200 200 200 
300 300 300 300 
400 300 300 300 
500 300 300 300 

对于第一个解决方案集,我可以使用1700作为每个用户的最佳页面分配数量,并继续分配书页直到,当前划线页面总和> = 1700.但是,第二个解决方案没有任何模式任何?

这是我生成解决方案的代码:

private void processScribes(){
        int[][] bookScribe = new int[numOfBooks][numOfScribes];
        //set first row to b1 page number
        for (int j = 0; j < numOfScribes; ++j)
            bookScribe[0][j] = bookPages[0];

        //set first column to sum of book page numbers
        for (int row = 1; row < numOfBooks; ++row)
            bookScribe[row][0] = bookScribe[row - 1][0] + bookPages[row]; 

        //calculate the kth scribe using dp
        for (int i = 1; i < numOfBooks; ++i){
            for (int j = 1; j < numOfScribes; ++j){
                //calculate minimum of maximum page numbers
                //from k = l + 1 to i
                //calculate sum 
                int minValue = 1000000;
                for (int k = 0; k < i - 1; ++k){
                    int prevValue = bookScribe[i - k][j - 1];
                    int max = 0;
                    int sumOflVals = 0;
                    for (int l = k + 1; l <= i; ++l){
                        sumOflVals = sumOflVals + bookPages[l];
                    }
                    if (prevValue > sumOflVals){
                        max = prevValue;
                    }
                    else
                        max = sumOflVals;
                    if (max < minValue )
                        minValue = max;
                }
                if (minValue == 1000000)
                    minValue = bookScribe[i][0];
                //store minvalue at [i][j]
                bookScribe[i][j] = minValue;
            }
        }

        //print bookScribes
        for (int i = 0; i < numOfBooks; ++i){
            for (int j = 0; j < numOfScribes; ++j)
                System.out.print(bookScribe[i][j] + " ");
            System.out.println();
        }
        System.out.println();
    }

这里有什么指示?它是解决方案的解释还是我在代码中翻译重复的错误?

最佳答案 不确定您的解决方案,但这是一个直观的递归方法与memoization.让有n页的书有书页[i].还有m个订阅者.如果我们只给了i,i 1 ….. n并且只有j个订阅者来完成这项工作,那么让dp [i] [j]成为问题的答案.以下是带有memoization的递归伪代码

    //dp[][] is memset to -1 from main
    // Assuming books are numbered 1 to n
    // change value of MAX based on your constraints
    int MAX = 1000000000;
    int rec(int position , int sub )
    {
          // These two are the base cases
          if(position > n)
          {
             if(sub == 0)return 0;
             return MAX;
          }
          if(sub == 0)
          {
              if(position > n)return 0;
              return MAX;
          }

          // If answer is already computed for this state return it
          if(dp[position][sub] != -1)return dp[position][sub];

          int ans = MAX,i,sum = 0;
          for(i = position; i <= n;i++)
          {
             sum += pages[i];
             // taking the best of all possible solutions
             ans = min(ans,max(sum,rec(i+1,sub-1)));
          }
          dp[position][sub]=ans;
          return ans; 
    }

    //from main call rec(1,m) which is your answer

您可以通过动态编程将其转换为迭代解决方案,它将在时间和空间上具有相同的复杂性.空间为O(n.m),时间为O(n ^ 2.m).

编辑
下面看一下测试用例Book Copying Code 上代码的运行版本.它不仅可以找到最佳答案,还可以使用它打印最佳分配(我没有包含在上面的伪代码中). (点击右上角的叉子,它会继续运行
你的测试用例,输入格式与你的相同).输出将是最佳答案,然后是最佳分配.如果您对代码有疑问,请发表评论.

点赞