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数组可以求出最佳方案,然后按照题中要求输出即可。

poj1093
#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;

}
View Code

 

你可能感兴趣的:(poj)