题目描述
给你一串由小写字母组成的字符串,希望你把它划分成一些小段,使得每一小段字符串中的字母
都不相同,并且希望分的段数尽量少。
然后,把这些小段按字典序排序后输出,中间由一个空格分隔。
例如:字符串 ”nnsmpmn”,最少分成 3 小段:”n”,”nsmp”,”mn”。
排序后输出:mn n nsmp
注意,有时候符合上面要求的方案可能有多个,就要输出排序后字典序最小的那个。
例如:字符串 ”aba” 可以有 2 种划分:a/ba 和 ab/a,排序后分别是:”a ba” 和 ”a ab”。
应该输出:a ab
输入输出格式
输入格式:
第一行包含 1 个正整数 k,表示有 k 组任务。
之后 k 行每行包含 1 个由小写字母组成的字符串 S。
输出格式:
共 k 行每行表示一个字符串的拆分方案。
输入输出样例
输入样例#1:
4 facetiously aaaaa aba babb
输出样例#1:
facetiously a a a a a a ab ab b b
说明
对于 30% 的数据:|S| ≤ 10; 对于 100% 的数据:k ≤ 10,|S| ≤ 50。
分析:细节题害死人QAQ.
显然这是一道dp题,设f[i]为1~i位的最优结果,要记录一个二元组:分了多少个、分的字符串是啥,然后f[i] = min{f[j] + t},这个加法和min要我们自己来定义.总之就是细节题.
以后不要轻易用string了,在类里面开一个string数组总是报错.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <string> #include <cmath> using namespace std; int k; bool vis[300]; char S[60]; struct node { int tot; char ss[60]; }; struct node2 { int cnt; node s[60]; }f[600]; bool cmp2(node a, node b) { for (int i = 1; i <= min(a.tot, b.tot); i++) { if (a.ss[i] != b.ss[i]) return a.ss[i] < b.ss[i]; } return a.tot < b.tot; } bool cmp(node2 a, node2 b) { if (a.cnt != b.cnt) return a.cnt < b.cnt; for (int i = 1; i <= a.cnt; i++) return cmp2(a.s[i],b.s[i]); } int main() { scanf("%d", &k); while (k--) { scanf("%s", S + 1); int sizee = strlen(S + 1); for (int i = 1; i <= sizee; i++) f[i].cnt = sizee + 1; for (int i = 1; i <= sizee; i++) { memset(vis, false, sizeof(vis)); for (int j = i - 1; j >= 0; j--) { if (vis[S[j + 1] - 'a']) break; vis[S[j + 1] - 'a'] = 1; node2 t = f[j]; t.cnt++; for (int k = j + 1; k <= i; k++) { t.s[t.cnt].tot++; t.s[t.cnt].ss[k - j] = S[k]; } sort(t.s + 1, t.s + 1 + t.cnt, cmp2); if (cmp(t, f[i])) f[i] = t; } } for (int i = 1; i <= f[sizee].cnt; i++) { for (int j = 1; j <= f[sizee].s[i].tot; j++) cout << f[sizee].s[i].ss[j]; printf(" "); } cout << endl; } return 0; }