poj1093
题意:给出一个句子和要求整理后每行包含的字符数,要求将其整理为一种总badness最小的形式。设每个空格长度为n,单个空格的badness计算公式为(n-1)^2。总badness等于所有空格的badness的总和。给出整理后的格式。在badness最小的前提下,在分配一行中的空格时要让前面的空格尽量少。如果一个单词单占一行,badness为500。
分析:动态规划。f[i]表示前i个单词的最小badness是多少。f[i]=f[i-j]+cost(i-j,j);。cost(a,b)表示从单词a+1到单词b的放在一行中最小badness是多少。
并用from[i]存储f[i]是从哪个位置计算得来的值,即最后一次更新f[i]时i-j是几,即f[i]所在行的上一行的最后一个单词是第几个。
我们利用from数组可以求出最佳方案,然后按照题中要求输出即可。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; const int maxn = 1000; int n, wordsnum; string words[maxn]; int sum[maxn]; int f[maxn][maxn]; int from[maxn][maxn]; void turntowords(string st) { int i = 0; while (1) { i = 0; while (st[i] != ' ' && i < signed(st.length())) i++; words[wordsnum++] = st.substr(0, i); sum[wordsnum] = i + sum[wordsnum - 1]; if (i == signed(st.length())) break; st.erase(0, i); while (st[0] == ' ') st.erase(0, 1); } } void init() { string st; wordsnum = 0; memset(sum, 0, sizeof(sum)); getchar(); while (1) { getline(cin, st); if (st == "") break; turntowords(st); } } int cost(int start, int end) { int left, right, tot, len; if (end - start == 1) return 500; tot = n - (sum[end] - sum[start]); len = tot / (end - start - 1); left = end - start - 1 - tot % (end - start - 1); right = tot % (end - start - 1); return left * (len - 1) * (len - 1) + right * len * len; } void work() { int i, j, k; memset(f, -1, sizeof(f)); f[0][0] = 0; for (i = 1; i <= wordsnum; i++) for (j = 1; j <= wordsnum; j++) for (k = 1; k <= j && j - k >= i - 1 && n - (sum[j] - sum[j - k]) >= k - 1; k++) if (f[i - 1][j - k] != -1 && (f[i][j] > f[i - 1][j - k] + cost(j - k, j) || f[i][j] == -1)) { f[i][j] = f[i - 1][j - k] + cost(j - k, j); from[i][j] = k; } } void printline(int start, int end) { int left, tot, len, i, j; if (end - start == 1) { cout << words[start] << endl; return; } tot = n - (sum[end] - sum[start]); len = tot / (end - start - 1); left = end - start - 1 - tot % (end - start - 1); for (i = start; i < end - 1; i++) { cout << words[i]; for (j = 0; j < len; j++) printf(" "); if (i - start + 1 > left) printf(" "); } cout << words[end - 1] << endl; } void output() { int i, best = 1000000000, besti; for (i = 0; i <= wordsnum; i++) if (f[i][wordsnum] < best && f[i][wordsnum] >= 0) { best = f[i][wordsnum]; besti = i; } int line[maxn]; int j = wordsnum; for (i = besti; i > 0; i--) { line[i] = from[i][j]; j -= from[i][j]; } j = 0; for (i = 1; i <= besti; i++) { printline(j, j + line[i]); j += line[i]; } cout << endl; } int main() { //freopen("D:\\t.txt", "r", stdin); while (cin >> n && n != 0) { init(); work(); output(); } return 0; }