大致题意:每次从一个字符串的左或者右边取一个字符,直到字符串空构成了一个新的满足字典序最小的串。
这题贪心法的代码如下:
#define LOCAL
#include <iostream>
#include <fstream>
using namespace std;
const int maxn = 2000 + 10;
char S[maxn];
int n;
void solve()
{
// 贪心的策略:比较左右那个比较小,设置一个标志位,如果左边比较小则标志位true
// 然后根据标志位输出左或者右,并且将左右的游标改变(a++ b-- )。如果两边相等
// 则进一步比较之
int a = 0, b = n - 1, nc = 0;
while (a <= b) {
bool left = false;
for (int i = 0; a + i <= b - i; ++i) {
if (S[a + i] < S[b - i]) {
left = true;
break;
}
if (S[a +i] > S[b - i]) {
left = false;
break;
}
}
if (left) {
cout << S[a++];
nc++;
} else {
cout << S[b--];
nc++;
}
if (nc % 80 == 0) {
cout << endl;
}
}
if (nc % 80)
cout << endl;
}
int main()
{
#ifdef LOCAL
freopen("input.txt", "r", stdin);
#endif
// Input N
cin >> n;
// Input S
for (int i = 0; i < n; ++i) {
cin >> S[i];
}
solve();
return 0;
}
核心部分的谈心如下:
for (int i = 0; a + i <= b - i; ++i) {
if (S[a + i] < S[b - i]) {
left = true;
break;
}
if (S[a +i] > S[b - i]) {
left = false;
break;
}
}
这部分表示了如果左右的字符相等,那么就继续比较直到小于的情况出现了,那么就选择更小的那一边开始取,如果字符串是类似下面的形式:
5 4 3 2 1 3 4 5
那么应该选择右边的 5 ,得到的结果就是最优解。
若与上的字符相反,如下:
1 2 3 4 5 3 2 1
得到了 1 1 2 2 3 3 4 5 这样的最优解验证是正确的。
但是这种终究叫做验证而不是证明,最近看张宇考研数学的课程讲到:“性质是由定义退出来的而不是计算出来的”。计算和验算仅仅是验证的工具而不是证明的工具!