题目描述
Farmer John 打算带领 N ( 1 ≤ N ≤ 2000 ) N(1≤N≤2000) N(1≤N≤2000)头奶牛参加一年一度的"全美农场主大奖赛"。在这场比赛中,每个参赛者必须让他的奶牛排成一列,然后带领这些奶牛从裁判面前依此走过。
今年,竞赛委员会在接受报名时,采用了一种新的登记规则:取每头奶牛名字的首字母,按照它们在队伍中的次序排成一列。将所有队伍的名字按字典序升序排序,从而得到出场顺序。
FJ 由于事务繁忙,他希望能够尽早出场。因此他决定重排队列。
他的调整方式是这样的:每次,他从原队列的首端或尾端牵出一头奶牛,将她安排到新队列尾部。重复这一操作直到所有奶牛都插入新队列为止。
现在请你帮 FJ 算出按照上面这种方法能排出的字典序最小的队列。
输入格式
第一行一个整数
N
N
N。
接下来 N N N 行每行一个大写字母,表示初始队列。
输出格式
输出一个长度为
N
N
N 的字符串,表示可能的最小字典序队列。
每输出 80 80 80 个字母需要一个换行。
输入输出样例
输入
6
A
C
D
B
C
B
输出
ABCBCD
思路分析
简化题目为:
每一次从旧数组的前或后选择一个字符加入新的数组的后方,使得最终新数组字典序最小。
贪心,局部最优,肯定选两边小的。
但是,如果一样怎么办? 两侧都向内查找一个
AC的C++代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int n;
char s1[2010],s2[2010];
cin >> n;
for (int i = 0; i < n; i++)
cin >> s1[i];
int le = 0, ri = n - 1,i = 0;
while (le < ri)
{
if (s1[le] < s1[ri])
{
s2[i] = s1[le];
le++;
i++;
}
else if (s1[le] > s1[ri])
{
s2[i] = s1[ri];
ri--;
i++;
}
else//头尾相等
{
int m=0;//m为连续几个数相等
for (m = 1; ; m++)
{
if (s1[le + m] != s1[ri - m])//第一次出现不一样的数
break;
else
continue;
}
if (s1[le + m] < s1[ri - m])
{
for (int x = 0; x <= m; x++)
s2[i + x] = s1[le + x];
i += m + 1;
le += m + 1;
}
else
{
for (int x = 0; x <= m; x++)
s2[i + x] = s1[ri - x];
i += m + 1;
ri -= m + 1;
}
}
}
s2[n-1] = s1[le];
for (int i = 0; i < n; i++)
{
cout << s2[i] ;
if ((i + 1) % 80 == 0)
cout << endl;
}
return 0;
}