Dynamic programming - state determination

I recently encountered this problem in a dynamic programming curriculum, and I honestly have no idea how to determine the appropriate state.

You are assigned N (1 <= N <= 70) and M (1 <= M <= N). For each paragraph i, the lines PL_i (1 <= PL_i <= 100) and links no more than one digit are required. Each figure is referenced exactly once (i.e., no two paragraphs can refer to the same figure, and for each figure there is a paragraph that refers to it). Each figure requires PF_i (1 <= PF_i <= = 100).

The task is to distribute these numbers and paragraphs on paper in the order in which they are indicated, where one paper is suitable for lines L maximum. Not a single paragraph or figure is too large to fit a single paper. If paragraph x , placed on paper x_p , refers to the number y , then y must be placed on paper x_p - 1 or x_p or x_p + 1 .

We need to find the minimum number of lines (and therefore pages) for distribution in order to distribute all the numbers and paragraphs. Any help would be greatly appreciated. Thanks in advance!

+8
algorithm dynamic state dynamic-programming
source share
4 answers

there is a common problem that you need to reorder paragraphs P and figures P of simple (P, F) order or (F, P) order.

Placement in the document: (P1, F1), (P2, F2), (P3, F3), where each tuple (P, F) can be of any order (P, F) or (F, P) there are some Fs, length which is 0, which means that F.

The challenge is to find the order for each pair (P, F).

One solution to finding the smallest number of Paiges is to apply this rule

lines_total = MIN(lines(P,F),lines(F,P)) + remaining() //this is custom addition 

Well, there is no prototype of this function, but for C it goes like

 calc_spend_lines(pfpairs * pairs) 

Where pfpaires

 typedef struct { int P; int F; } pfpaires; 

And you know that you have reached the end when P = 0. For example,

All you have to do is make a function that implements this special + sign, meaning page breaks and dead lines.

This gives an O (N) solution for the minimum number of pages, but not the number of rows, since your final condition will be 0.

If you want to minimize the number of lines, you can use bisection, where you set the termination condition to something else instead of 0, and this gives you

O (N * log (L)) solution

EDIT
Since there may be other P between the current P and F, you just need to check instead of ((F, P), (P, F)) also check the blank page (N) so that the combo ((P, F) (P, N, P ), (P, P), (F, N, P)). The conclusion is that you are completing a complex algorithm, but with the same complexity. The point is that after you check one of the 4 orders, there is only one simple way to make optimal positioning, just the current state (lines) is a little more complicated.

+1
source share

As the DP state for the current page P, you can use an array (size L * 2), indexed by the number of lines, reserved on page P for numbers, a link from page P + 1 or (negated) number of lines needed on page P + 1 for images referenced from page P.

Each element of the array consists of two values:

  • x is the number of paragraphs distributed on pages 1 .. P;
  • some data needed to restore the paragraph / number distribution after completing the DP algorithm.

Use this array to calculate the array for the next page (P + 1). For each valid element of the array P, add new paragraphs ( x +1, x +2, ...) to the page P + 1, updating the corresponding elements of the array P + 1. Although it is possible, put the numbers indicated in these paragraphs on the page P, then on page P + 1, and then on page P + 2. Overwrite the elements of the P + 1 array that have lower x values ​​with higher values.

The time complexity for this algorithm is: O ( L * N ): the number of lines per page. Since the processing of each page is O (lines per page) - the average paragraphs per page.

+1
source share

It can be optimized, but this is a working solution:

 public class ParagraphsAndFigures {

  public static ArrayList<PageContent> generatePages(List<Paragraph> paragraphs, int L) { ArrayList<PageContent> pages = new ArrayList<PageContent>(); for (int i = 0; i < paragraphs.size() * 2; i++) { pages.add(new PageContent()); } int page = 0; for (Paragraph paragraph : paragraphs) { do { int cur = pages.get(page).linesReserved; int next = pages.get(page + 1).linesReserved; if (cur + paragraph.size < L) { cur += paragraph.size; if (paragraph.figure != null) { if (pages.get(page + 1).hasPicture()) { if (next + paragraph.figure.size < L) { pages.get(page).texts.add(paragraph); pages.get(page + 1).texts.add(paragraph.figure); pages.get(page).linesReserved += paragraph.size; pages.get(page + 1).linesReserved += paragraph.figure.size; break; // next paragraph } else { page++; continue; } } if (pages.get(page).hasPicture()) { if (cur + paragraph.figure.size < L) { pages.get(page).texts.add(paragraph); pages.get(page).texts.add(paragraph.figure); pages.get(page).linesReserved += paragraph.size; pages.get(page).linesReserved += paragraph.figure.size; break; // next paragraph } else { if (next + paragraph.figure.size < L) { pages.get(page).texts.add(paragraph); pages.get(page + 1).texts.add(paragraph.figure); pages.get(page).linesReserved += paragraph.size; pages.get(page + 1).linesReserved += paragraph.figure.size; break; // next paragraph } page++; continue; } } if (page != 0 && pages.get(page - 1).hasPicture()) { int prev = pages.get(page - 1).linesReserved; if (prev + paragraph.figure.size < L) { pages.get(page).texts.add(paragraph); pages.get(page - 1).texts.add(paragraph.figure); pages.get(page).linesReserved += paragraph.size; pages.get(page - 1).linesReserved += paragraph.figure.size; break; // next paragraph } else { if (cur + paragraph.figure.size < L) { pages.get(page).texts.add(paragraph); pages.get(page).texts.add(paragraph.figure); pages.get(page).linesReserved += paragraph.size; pages.get(page).linesReserved += paragraph.figure.size; break; // next paragraph } if (next + paragraph.figure.size < L) { pages.get(page).texts.add(paragraph); pages.get(page + 1).texts.add(paragraph.figure); pages.get(page).linesReserved += paragraph.size; pages.get(page + 1).linesReserved += paragraph.figure.size; break; // next paragraph } page++; } } if (page != 0) { int prev = pages.get(page - 1).linesReserved; if ( prev + paragraph.figure.size < L) { pages.get(page).texts.add(paragraph); pages.get(page - 1).texts.add(paragraph.figure); pages.get(page).linesReserved += paragraph.size; pages.get(page - 1).linesReserved += paragraph.figure.size; break; // next paragraph } } if (cur + paragraph.figure.size < L) { pages.get(page).texts.add(paragraph); pages.get(page).texts.add(paragraph.figure); pages.get(page).linesReserved += paragraph.size; pages.get(page).linesReserved += paragraph.figure.size; break; // next paragraph } if (next + paragraph.figure.size < L) { pages.get(page).texts.add(paragraph); pages.get(page + 1).texts.add(paragraph.figure); pages.get(page).linesReserved += paragraph.size; pages.get(page + 1).linesReserved += paragraph.figure.size; break; // next paragraph } page++; } } page++; } while (true); } return pages; } } 

And tests:

 public class ParagraphsAndFiguresTest { @Test public void pageGeneration1() throws Exception { // given ArrayList paragraphs = new ArrayList(); paragraphs.add(new Paragraph(20,21)); paragraphs.add(new Paragraph(22,23)); paragraphs.add(new Paragraph(24,25)); 
// when ArrayList<PageContent> pageContents = ParagraphsAndFigures.generatePages(paragraphs, 50); // then assertThat(transformToList(pageContents), is(asList("20", "21", "p0" ,"22" ,"23", "p1" ,"24" ,"25", "p2"))); } @Test public void pageGeneration2() throws Exception { // given ArrayList<Paragraph> paragraphs = new ArrayList<Paragraph>(); paragraphs.add(new Paragraph(10,11)); paragraphs.add(new Paragraph(28,21)); paragraphs.add(new Paragraph(22,23)); // when ArrayList<PageContent> pageContents = ParagraphsAndFigures.generatePages(paragraphs, 50); // then assertThat(transformToList(pageContents), is(asList("10", "11" ,"28", "p0" ,"21", "22" , "p1" ,"23", "p2"))); } @Test public void pageGeneration3() throws Exception { // given ArrayList<Paragraph> paragraphs = new ArrayList<Paragraph>(); paragraphs.add(new Paragraph(10,11)); paragraphs.add(new Paragraph(12,30)); paragraphs.add(new Paragraph(13,19)); // when ArrayList<PageContent> pageContents = ParagraphsAndFigures.generatePages(paragraphs, 50); // then assertThat(transformToList(pageContents), is(asList("10", "11" ,"12", "13", "p0" ,"30", "19" , "p1" ))); } @Test public void pageGeneration4() throws Exception { // given ArrayList<Paragraph> paragraphs = new ArrayList<Paragraph>(); paragraphs.add(new Paragraph(10,11)); paragraphs.add(new Paragraph(30,12)); paragraphs.add(new Paragraph(13,16)); // when ArrayList<PageContent> pageContents = ParagraphsAndFigures.generatePages(paragraphs, 50); // then assertThat(transformToList(pageContents), is(asList("10", "11" ,"12", "16", "p0" ,"30", "13" ,"p1" ))); } @Test public void pageGeneration5() throws Exception { // given ArrayList<Paragraph> paragraphs = new ArrayList<Paragraph>(); paragraphs.add(new Paragraph(31,32)); paragraphs.add(new Paragraph(17,21)); paragraphs.add(new Paragraph(30,35)); // when ArrayList<PageContent> pageContents = ParagraphsAndFigures.generatePages(paragraphs, 50); // then assertThat(transformToList(pageContents), is(asList("31", "p0", "32", "17", "p1", "21", "p2", "30", "p3", "35", "p4"))); } private List<String> transformToList(ArrayList<PageContent> pageContents) { List<String> result = new ArrayList<String>(); for (int i = 0; i < pageContents.size(); i++) { PageContent pageContent = pageContents.get(i); if (!pageContent.texts.isEmpty()) { for (Text text : pageContent.texts) { result.add(String.valueOf(text.size)); } result.add("p"+i); } } return result; } }

And structures: public class PageContent {int linesReserved; Text collection = new ArrayList ();

public boolean hasPicture () {for (Text: text) {if (text instanceof Figure) {return true; }} return false; }} public class Text {protected int size; } public class Figure extends Text {} public class Paragraph extends the text {public Paragraph (int size, int fSIze) {this.size = size; this.figure = new Figure (); this.figure.size = fSIze; } Drawing; } Code>

+1
source share

First, I would recommend creating a recursive method.

Choose the best option: start with a paragraph or a picture.

At each step, choose the best option: add a pagebreak, add the next image, add the next paragraph. A simple state machine will help to eliminate the prohibited options (for example, 2 lines per line), but this is not necessary.

When the recursive solution is tested, you can convert it to dynamic programming from top to bottom or from bottom to top, as described in most algorithmic courses on DP.

-one
source share

All Articles