这是DP中一个非常著名的问题,有人可以帮助可视化它的递归部分。如何生成排列或组合。
问题参考。 https://www.geeksforgeeks.org/dynamic-programming-set-18-word-wrap/
答案 0 :(得分:0)
假定最大行宽为L(证明文本T合理)的想法是考虑文本的所有后缀(为了精确地形成后缀,请考虑单词而不是字符)。 动态编程不过是“谨慎的蛮力”。 如果您考虑采用蛮力方法,则需要执行以下操作。
相反,我们只考虑问题,以找出将单词放在行首的成本。 通常,我们可以将DP(i)定义为将第(i-1)个单词视为行的开头的代价。
如何为DP(i)形成递归关系?
如果第j个单词是下一行的开头,则当前行将包含单词[i:j)(j排他),而第j个单词作为下一行的开头的开销将为DP(j)。 因此,DP(i)= DP(j)+在当前行中放置单词[i:j)的成本 由于我们希望使总成本最小化,因此可以定义DP(i)。
重复关系:
DP(i)=最小{DP(j)+在当前行中放置单词[i:j的成本} 对于[i + 1,n]中的所有j
注意j = n表示下一行没有剩余的单词。
基本情况:DP(n)= 0 =>此时,没有可写的字了。
总结:
现在,即使我们得出证明文本合理的最低成本,我们也需要通过跟踪上面表达式中选择为最小值的j值来解决原始问题,以便以后可以使用相同的值进行打印找出合理的文字。这个想法是保留父指针。
希望这可以帮助您了解解决方案。以下是上述想法的简单实现。
public class TextJustify {
class IntPair {
//The cost or badness
final int x;
//The index of word at the beginning of a line
final int y;
IntPair(int x, int y) {this.x=x;this.y=y;}
}
public List<String> fullJustify(String[] words, int L) {
IntPair[] memo = new IntPair[words.length + 1];
//Base case
memo[words.length] = new IntPair(0, 0);
for(int i = words.length - 1; i >= 0; i--) {
int score = Integer.MAX_VALUE;
int nextLineIndex = i + 1;
for(int j = i + 1; j <= words.length; j++) {
int badness = calcBadness(words, i, j, L);
if(badness < 0 || badness == Integer.MAX_VALUE) break;
int currScore = badness + memo[j].x;
if(currScore < 0 || currScore == Integer.MAX_VALUE) break;
if(score > currScore) {
score = currScore;
nextLineIndex = j;
}
}
memo[i] = new IntPair(score, nextLineIndex);
}
List<String> result = new ArrayList<>();
int i = 0;
while(i < words.length) {
String line = getLine(words, i, memo[i].y);
result.add(line);
i = memo[i].y;
}
return result;
}
private int calcBadness(String[] words, int start, int end, int width) {
int length = 0;
for(int i = start; i < end; i++) {
length += words[i].length();
if(length > width) return Integer.MAX_VALUE;
length++;
}
length--;
int temp = width - length;
return temp * temp;
}
private String getLine(String[] words, int start, int end) {
StringBuilder sb = new StringBuilder();
for(int i = start; i < end - 1; i++) {
sb.append(words[i] + " ");
}
sb.append(words[end - 1]);
return sb.toString();
}
}