首先贴题目如下:
http://topcoder.bgcoder.com/print.php?id=204
TopCoder problem "PeopleCircle" used in SRM 147 (Division I Level One , Division II Level Two)
Problem Statement | |||||||||||||
There are numMales males and numFemales females arranged in a circle. Starting from a given point, you count clockwise and remove theK'th person from the circle (where K=1 is the person at the current point, K=2 is the next person in the clockwise direction, etc...). After removing that person, the next person in the clockwise direction becomes the new starting point. After repeating this procedurenumFemales times, there are no females left in the circle. Given numMales, numFemales and K, your task is to return what the initial arrangement of people in the circle must have been, starting from the starting point and in clockwise order. For example, if there are 5 males and 3 females and you remove every second person, your return String will be "MFMFMFMM". | |||||||||||||
Definition | |||||||||||||
| |||||||||||||
Constraints | |||||||||||||
- | numMales is between 0 and 25 inclusive | ||||||||||||
- | numFemales is between 0 and 25 inclusive | ||||||||||||
- | K is between 1 and 1000 inclusive | ||||||||||||
Examples | |||||||||||||
0) | |||||||||||||
| |||||||||||||
1) | |||||||||||||
| |||||||||||||
2) | |||||||||||||
| |||||||||||||
3) | |||||||||||||
| |||||||||||||
4) | |||||||||||||
|
算法本身不难,本文提供2个。
- 基于list的算法:
算法挺容易想到的,就是构造list,模拟往后数的动作,往前回挪指针,然后list::insert进去,之后,把最后的位置设为初始位置,边界条件需要注意。另外的trick是换算reverse_iterator与iterator。
贴代码如下:
#include <iostream>
#include <list>
#include <string>
using namespace std;
void MoveStep(list<char>::iterator* it, int move_step, list<char>* l) {
for (int i = 0; i < move_step; ++i) {
if ((*it) == l->end()) {
*it = l->begin();
}
++(*it);
}
}
string ListToString(const list<char>& l) {
int idx = 0;
string str(l.size(), '_');
for (list<char>::const_iterator it = l.begin();
it != l.end(); ++it) {
str[idx++] = *it;
}
return str;
}
string Revert(int num_males, int num_females, int step) {
list<char> l(num_males, 'M');
list<char>::iterator add_it = l.begin();
for (int i = 0; i < num_females; ++i) {
// list::insert can't use reverse_iterator,
// and the inserted iterator will be before add_it.
// Since we can't use reverse_iterator, we ought to calculate
// the steps to move after instead of the ones move back.
l.insert(add_it, 'F');
int size = l.size();
int move_step = (size - (step % size));
MoveStep(&add_it, move_step, &l);
}
cout << "before adjust:\t" << ListToString(l) << endl;
// to set add_it as front.
for (list<char>::iterator it = l.begin(); it != add_it;) {
l.push_back(*it);
++it;
// Note: pop_front() should be after iterator moves.
l.pop_front();
}
return ListToString(l);
}
int main() {
cout << "5, 3, 2" << endl;
cout << Revert(5, 3, 2) << endl;
cout << "7, 3, 1" << endl;
cout << Revert(7, 3, 1) << endl;
cout << "25, 25, 1000" << endl;
cout << Revert(25, 25, 1000) << endl;
cout << "5, 5, 3" << endl;
cout << Revert(5, 5, 3) << endl;
cout << "1, 0, 245" << endl;
cout << Revert(1, 0, 245) << endl;
}
- 直接基于string的算法:
初始都是M的string,每次数K格,从0开始数,如果是M就+1,F就跳过,数够个数后将当前位置设成F,以此类推。通过mod的关系,可以做个优化。trick在于:move_step与count的定义与计算方式不同,见code注释
#include <iostream>
#include <string>
using namespace std;
string PeopleCircle(int num_males, int num_females, int step) {
int len = num_males + num_females;
string result(len, 'M');
int index = 0;
for (int i = 0; i < num_females; ++i) {
int count = 0;
// Including the 0th element, the actually move_step is step-1.
int move_step = (step - 1) % (len - i);
while (true) {
if (result[index] != 'F') {
++count;
// Including the 0th element, the count should reach original step mode.
if (count == move_step+1) {
break;
}
}
index = (index + 1) % len;
}
result[index] = 'F';
index = (index + 1) % len;
}
return result;
}
int main() {
cout << "5, 3, 2" << endl;
cout << PeopleCircle(5, 3, 2) << endl;
cout << "7, 3, 1" << endl;
cout << PeopleCircle(7, 3, 1) << endl;
cout << "25, 25, 1000" << endl;
cout << PeopleCircle(25, 25, 1000) << endl;
cout << "5, 5, 3" << endl;
cout << PeopleCircle(5, 5, 3) << endl;
cout << "1, 0, 245" << endl;
cout << PeopleCircle(1, 0, 245) << endl;
}