UVA_10602
这个题目可以用贪心去做。
我们不妨先看一下这样一个贪心的思路,每次我们都去拼需要press的字符数最少的单词,这样做是否可以呢?实际上我们可以找到这样一个反例,
3
aaaab
aaaabbb
aaaac
如果按这样的贪心思路就会输出
9
aaaab
aaaac
aaaabbb
但实际上正确的结果为
8
aaaab
aaaabbb
aaaac
尽管上面的想法是错误的,但我们也或多或少会得到些启发,对于这组测试数据之所以没有最优,是由于相比最优的结果多press了一个b,而之所以多press了这个b,是由于我们一开始没有去拼和aaaab有最大前缀的aaaabbb,而选择了去拼aaaac,换句话说,我们press的字符的数量是由相邻的字符串的公共前缀的大小决定的,如果按公共前缀先长后短的顺序去拼字符串,那么后面短了的部分是不会影响press的字符数的,然而如果先拼公共前缀短的字符串,我们就会付出更多的press的代价,而这部分代价就是短的公共前缀变成长的公共前缀所需press的字符数。
因此,正确的贪心策略是每次选取公共前缀最长的字符串去拼。
#include<stdio.h>
#include<string.h>
#define MAXD 110
#define INF 0x3f3f3f3f
int N, g[MAXD][MAXD], vis[MAXD], p[MAXD];
char b[MAXD][MAXD];
void solve()
{
int i, j, k, t, cur, ans, max;
scanf("%d", &N);
for(i = 0; i < N; i ++)
scanf("%s", b[i]);
cur = p[0] = 0;
ans = strlen(b[0]);
memset(vis, 0, sizeof(vis));
for(i = 1; i < N; i ++)
{
vis[cur] = 1;
max = -1;
for(j = 0; j < N; j ++)
if(!vis[j])
{
for(k = 0; b[cur][k] && b[j][k] && b[cur][k] == b[j][k]; k ++);
if(k > max)
{
max = k;
t = j;
}
}
ans += strlen(b[t]) - max;
cur = p[i] = t;
}
printf("%d\n", ans);
for(i = 0; i < N; i ++)
printf("%s\n", b[p[i]]);
}
int main()
{
int t;
scanf("%d", &t);
while(t --)
{
solve();
}
return 0;
}