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 = ; int n, wordsnum;
string words[maxn];
int sum[maxn];
int f[maxn][maxn];
int from[maxn][maxn]; void turntowords(string st)
{
int i = ; while ()
{
i = ;
while (st[i] != ' ' && i < signed(st.length()))
i++;
words[wordsnum++] = st.substr(, i);
sum[wordsnum] = i + sum[wordsnum - ];
if (i == signed(st.length()))
break;
st.erase(, i);
while (st[] == ' ')
st.erase(, );
}
} void init()
{
string st; wordsnum = ;
memset(sum, , sizeof(sum));
getchar();
while ()
{
getline(cin, st);
if (st == "")
break;
turntowords(st);
}
} int cost(int start, int end)
{
int left, right, tot, len; if (end - start == )
return ;
tot = n - (sum[end] - sum[start]);
len = tot / (end - start - );
left = end - start - - tot % (end - start - );
right = tot % (end - start - );
return left * (len - ) * (len - ) + right * len * len;
} void work()
{
int i, j, k; memset(f, -, sizeof(f));
f[][] = ;
for (i = ; i <= wordsnum; i++)
for (j = ; j <= wordsnum; j++)
for (k = ; k <= j && j - k >= i - && n - (sum[j] - sum[j - k]) >= k - ; k++)
if (f[i - ][j - k] != - && (f[i][j] > f[i - ][j - k] + cost(j - k, j) || f[i][j] == -))
{
f[i][j] = f[i - ][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 == )
{
cout << words[start] << endl;
return;
}
tot = n - (sum[end] - sum[start]);
len = tot / (end - start - );
left = end - start - - tot % (end - start - );
for (i = start; i < end - ; i++)
{
cout << words[i];
for (j = ; j < len; j++)
printf(" ");
if (i - start + > left)
printf(" ");
}
cout << words[end - ] << endl;
} void output()
{
int i, best = , besti; for (i = ; i <= wordsnum; i++)
if (f[i][wordsnum] < best && f[i][wordsnum] >= )
{
best = f[i][wordsnum];
besti = i;
}
int line[maxn];
int j = wordsnum;
for (i = besti; i > ; i--)
{
line[i] = from[i][j];
j -= from[i][j];
}
j = ;
for (i = ; 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 != )
{
init();
work();
output();
}
return ;
}
poj1093的更多相关文章
- DP50题(转)
转自https://www.luogu.org/blog/cccx2016/dp50-ti-ti-hao dp50题: poj1014 poj1015 poj1018 poj1036 poj1038 ...
随机推荐
- Windows 防火墙出站 入站规则简单说明
1. Windows防火墙其实比linux的iptabels 要好用一些. 打开设置方式: 运行->输入control即可 选择系统和安全 2.win2019 以及改名字了 现在是 window ...
- Java对象与Map间相互转换
将Java对象转为一个Map,以及将map转为对应Java对象,代码如下: public class BeanMapUtil { private static ConcurrentHashMap< ...
- poj3368 Frequent values(线段树)
Description You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In ad ...
- 知识点【JavaScript模块化】
JavaScript模块化历程 JavaScript发展变迁大概是一下几个步骤: 工具(浏览器兼容) 组件(功能模块) 框架(功能模块组织) 应用(业务模块组织) 但是经过了长长的后天努力过程Java ...
- 【BZOJ4883】棋盘上的守卫(最小生成树)
[BZOJ4883]棋盘上的守卫(最小生成树) 题面 BZOJ 题解 首先\(n\)行\(m\)列的棋盘显然把行列拆开考虑,即构成了一个\(n+m\)个点的图.我们把格子看成边,那么点\((x,y)\ ...
- 【uoj34】 多项式乘法
http://uoj.ac/problem/34 (题目链接) 题意 求两个多项式的乘积 Solution 挂个FFT板子. 细节 FFT因为要满足$n$是$2$的幂,所以注意数组大小. 代码 // ...
- 【洛谷P1991】无线通讯网
题目大意:给定一个 N 个顶点的完全图,边有边权,现在要求使得图中所有顶点联通的情况下,第 M-1 大的边最小值是多少. 题解:所有点联通的最小要求是所有点和连接这些点的边构成原图的一棵生成树,那么问 ...
- oracle数据库连接池查看
select username , count(*), machine from v$session where username is not null group by username, mac ...
- 界面编程之QT绘图和绘图设备20180728
/*******************************************************************************************/ 一.绘图 整 ...
- hdu 1358 Period 最小循环节
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1358 分析:已知字符串,求其由最小循环节构成的前缀字符串. /*Period Time Limit: ...