Я написал следующий код для вычисления количества изменений, необходимых для упорядочения строки, содержащей неупорядоченный A e B, в соответствии с порядком, который должен быть «A [... A] B [... B]». (функция countChanges
).
Алгоритм (countChanges
), используемый для подсчета изменений, действует в три этапа:
Шаг 1: подсчитывает, сколько «A» символы в строке (cnt
).
Шаг 2: сканирует, сколько символов 'B' есть в первых cnt
символах строки, увеличивая счетчик (sum
) для каждого обнаруженного «B».
Шаг 3: сканирует, сколько символов «A» осталось в оставшихся символах строки после 2-го шага, увеличив счетчик (sum
) для каждого обнаруженного «A».
В конце функции sum
- ожидаемый результат.
Код также вычисляет и выполняет минимальное число свопы, необходимые для получения строки, упорядоченной в соответствии с требованием.
Код содержит две функции оценки (код под main
):
cntChanges
. Он вычисляет необходимое количество изменений (код дает результат как foreseen changes
).
executeSwaps
. Он выполняет обмен строк, подсчитывает их и может отображать или не отображать выполненные шаги.
Результат кода:
Do you have a code composed of A and B? [y]es/[n]o/[I] do it/[q]uit y
Insert your code? BABA
Do you want to print swap steps? [y]es/[n]o y
Input: BABA
Step 1 BABA swap(3,0) ==> AABB
Result AABB performed with 1 swap - foreseen changes 2
-
Do you have a code composed of A and B? [y]es/[n]o/[I] do it/[q]uit n
How much codes do you want to generate? 5
What's your preferred length for all generated codes? 10
Do you want to print swap steps? [y]es/[n]o y
Input: AAAAABAABB
Step 1 AAAAABAABB swap(7,5) ==> AAAAAAABBB
Result AAAAAAABBB performed with 1 swap - foreseen changes 2
--
Input: ABBABAAABA
Step 1 ABBABAAABA swap(9,1) ==> AABABAAABB
Step 2 AABABAAABB swap(7,2) ==> AAAABAABBB
Step 3 AAAABAABBB swap(6,4) ==> AAAAAABBBB
Result AAAAAABBBB performed with 3 swaps - foreseen changes 6
--
Input: AAABBAABBB
Step 1 AAABBAABBB swap(6,3) ==> AAAABABBBB
Step 2 AAAABABBBB swap(5,4) ==> AAAAABBBBB
Result AAAAABBBBB performed with 2 swaps - foreseen changes 4
--
Input: BABAABBABB
Step 1 BABAABBABB swap(7,0) ==> AABAABBBBB
Step 2 AABAABBBBB swap(4,2) ==> AAAABBBBBB
Result AAAABBBBBB performed with 2 swaps - foreseen changes 4
--
Input: AAABAABAAA
Step 1 AAABAABAAA swap(9,3) ==> AAAAAABAAB
Step 2 AAAAAABAAB swap(8,6) ==> AAAAAAAABB
Result AAAAAAAABB performed with 2 swaps - foreseen changes 4
-
Код:
#include <iostream>
#include <ctime>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
unsigned int executeSwaps(string &x, bool printSteps);
unsigned int cntChanges(const string& x);
unsigned int cntChangesJarod42(string const &x);
unsigned int cntChangesDamien(string const &x);
void questionToStart(int &c, size_t &cl, char &ync, char &ynps, string &x);
string generateCode(size_t n);
const char char1='A';
const char char2='B';
int main(void)
{
srand(static_cast<unsigned int>(time(nullptr)));
int c;
size_t cl;
char ync='n';
char ynps='n';
string x;
x.clear();
do {
questionToStart(c,cl,ync,ynps,x);
if (ync == 'q')
break;
for(int i=0;i<c;i++) {
unsigned int cnt=0;
if (ync=='n') {
x=generateCode(cl)
}
/* unsigned int fc2 = cntChangesJarod42(x);
unsigned int fc1 = cntChangesDamien(x);*/
unsigned int fc3 = cntChanges(x);
cout << "Input: " << x << endl;
cnt=executeSwaps(x, (ynps=='y')?1:0);
cout << "Result " << x << " performed with "
<< ((cnt>0)?to_string(cnt):"no")
<< " swap"
<< ((cnt>1)?"s ":" ") << " - foreseen changes " << fc3 << endl << "--" << endl;
/* << "foreseen changes (@Damien) " << fc1
<< " - foreseen changes (@Jarod42) " << fc2
<< endl << endl;*/
}
} while(ync != 'q');
return 0;
}
unsigned int cntChanges(const string& x)
{
const char * s;
unsigned int cnt=0,sum=0,i;
if (x.empty())
return 0;
s=x.c_str();i=0;
// count char1
while(*(s+i))
if (*(s+i++) == char1)
cnt++;
/* verify how much elements, from start to cnt,
* are different than char1 (equal to char2).
*/
for(i=0;i<cnt;i++)
if (*(s+i)==char2)
sum++;
cnt=static_cast<unsigned int>(strlen(s));
/* verify how much of the remaining elements
* are different than char2 (equal to char1).
*/
for(;i<cnt;i++)
if (*(s+i)==char1)
sum++;
return sum;
}
// @Jarod42
unsigned int cntChangesJarod42(const string& s)
{
if (s.empty()) { return 0; }
std::vector<std::size_t> switch_count(s.size());
{ // Count 'B' before index
unsigned int sum = 0;
std::size_t i = 0;
for (auto c : s) {
switch_count[i++] += sum;
sum += c == 'B';
}
}
{ // Count 'A' after the index
unsigned int sum = 0;
std::size_t i = 0;
for (auto c : std::string(s.rbegin(), s.rend())) {
switch_count[s.size() - 1 - i++] += sum;
sum += c == 'A';
}
}
return static_cast<unsigned int>(*std::min_element(switch_count.begin(), switch_count.end()));
}
// @Damien Algorithm
unsigned int cntChangesDamien (string const &x)
{
size_t n = x.length();
int cntCh_1 = 0, cntCh_2 = 0;
// there's nothing to swap!! :p
if (n < 2)
return 0;
for (size_t i = 0; i < n; ++i) {
if (x.at(i) == char1) {
cntCh_1++;
} else {
// x.at(i) is equal to char1
cntCh_1 = min (cntCh_2, cntCh_1);
// Now the foreseen swap are equal to cntCh1
cntCh_2++;
}
}
return static_cast<unsigned int>(std::min (cntCh_2, cntCh_1));
}
unsigned int executeSwaps(string &x, bool printSteps)
{
unsigned int cnt =0;
size_t apos=0;
size_t bpos=0;
// cout << "Start: " << x << " " << apos << " " << bpos << endl;
do {
apos=x.find_last_of(char1);
if (apos == string::npos)
break;
bpos=x.find_first_of(char2);
if (bpos == string::npos)
break;
if (apos>bpos) {
++cnt;
if (printSteps) {
cout << "Step " << cnt << " " << x << " swap(" << apos << "," << bpos <<") ==> ";
}
x.at(bpos)=char1;
x.at(apos)=char2;
if (printSteps)
cout << x << endl;
}
} while(apos>bpos);
return cnt;
}
string generateCode(size_t n)
{
string x;
x.clear();
size_t i,cb=0;
char ch;
if (n==0) {
n=rand()%10;
}
for (i=0;i<n-1;i++) {
ch = ( char1 + (rand()&1) );
if (ch == char2 )
cb++;
x +=ch;
}
if (cb==n-1) {
ch=char1;
} else if (cb==0) {
ch=char2;
} else {
ch=( char1 + (rand()&1) );
}
x += ch;
return x;
}
void questionToStart(int &c, size_t &cl, char &ync, char &ynps, string &x)
{
int ex=1;
do {
ex=1;
cout << "Do you have a code composed of "<<char1 << " and " << char2 <<"? [y]es/[n]o/[I] do it/[q]uit ";
cin >> ync;
switch(ync) {
case 'n':
cout << "How much codes do you want to generate? ";
cin >> c;
cout << "What's your preferred length for all generated codes? ";
cin >> cl;
break;
case 'I':
c=10; cl=(rand()&7)+9;
cout << c <<" attempts with " << cl << " characters long strings will be executed" << endl;
break;
case 'y':
c=1;
cout << "Insert your code? ";
cin >> x;
cl = x.length();
break;
case 'q':
break;
default:
ex=0;
}
} while(!ex);
if ( ync != 'q' ) {
if ( ync != 'I' ) {
cout << "Do you want to print swap steps? [y]es/[n]o ";
cin >> ynps;
} else {
ynps = 'y';
ync = 'n';
}
cout << endl;
}
}