题意:
本题与 "希尔排序" 无关, 应该是 "龟壳排序". "龟壳排序": 每次取一个龟壳(字符串), 把其移到最顶端, 其他的依次下移. 输入两组字符串, 第一组为初始串, 第二组为目标串. 求在使用 "龟壳排序" 的情况下, 将初始串变为目标串, 要求进行操作的次数最少.
思路:
要使初始串移动后达到目标串, 很好做, 但要求最少的移动次数, 就不会了...
以下思路来自: http://www.kaixinwenda.com/article-hhaile-8108911.html
以初始序列为准,设初始序列下标为i, 目的序列下标为j, 从n-1开始,如果两下标对应的字符串相等,下标同时减一,否则仅初始序列下标减一。那么目的序列中还未被成功匹配的字符串就是需要移动的字符串。要使移动次数最少,显然应该按未被处理的目的序列中字符串逆序移动(输出).
要点:
stl distance 会返回负数吗? 不会, 如果 distance 的第二个参数所指位置在第一个参数之前, 则会绕回来. (在 list 里是这样的, 但是对于其他 container 不是很确定是否会是这样的行为).
代码:
# include <iostream>
# include <string>
# include <cstdio>
# include <cstring>
# include <vector>
# include <algorithm>
# include <cctype>
# include <iterator>
# include <assert.h>
# include <list>
using namespace std;
typedef list<string>::const_iterator LIT;
// 获取需要开始往上移动的字符串的 iterator
LIT getTurtlesToClimb(const list<string>& original,
const list<string>& required) {
LIT oi = original.begin();
LIT ri = required.begin();
while (oi != original.end() && ri != required.end()) {
if (*oi == *ri) {
++oi;
++ri;
} else {
++oi;
}
}
return ri;
}
int main(int argc, char const *argv[])
{
#ifndef ONLINE_JUDGE
freopen("10152_i.txt", "r", stdin);
freopen("uva_o.txt", "w", stdout);
#endif
int numCase;
cin >> numCase;
while (numCase--) {
int numTurtles;
cin >> numTurtles;
cin.ignore(); // cin 之后要接 getline,一定要有 ignore
list<string> original;
list<string> required;
string line;
// input
for (int i=0; i<numTurtles; i++) {
getline(cin, line);
original.push_front(line);
}
for (int i=0; i<numTurtles; i++) {
getline(cin, line);
required.push_front(line);
}
// 注意这里输出的是 require 中剩下的字符串,而不是 original 中的
LIT ri = getTurtlesToClimb(original, required);
copy(ri, static_cast<LIT>(required.end()),
ostream_iterator<string>(cout, "\n"));
// 最后一个 case 也需要输出回车, 所以不需要以下行
//if (numCase > 0) cout << endl;
cout << endl;
}
return 0;
}
环境: C++ 4.5.3 - GNU C++ Compiler with options: -lm -lcrypt -O2 -pipe -DONLINE_JUDGE