Перестановки букв в слотах
Консольное приложение, язык C++. Есть 3 слота для букв, всего доступно 7 букв (условных A B C D E F G) для перестановок, без повторений (т.е. одну букву можно использовать только 1 раз). Позиция буквы в слове тоже не имеет значения (Т.е. ABC и CBA это одно и то же). За каждую определенную букву в слове приходится определенное действие (например, за букву А в слове, увеличить переменную NUM1 на 5, за каждую B - умножить NUM1 на 3, за каждую C - увеличить NUM1 на 6 и тд.).
Задача собственно, сгенерировать все возможные варианты этих перестановок и вывести их все в консоль со значением переменной, полученной при комбинации, а также определить наилучшую (т.е. ту комбинацию, которая привела к наибольшему значению) и вывести на экран в виде текстового сообщения.
Хотелось бы понять, как алгоритмически с программной точки зрения реализовать этот процесс. Пока мыслей нет на этот счет, в качестве крайнего варианта единственное что приходит в голову это посчитать количество перестановок математически (7x6x5), получаем 210 вариантов, и задать эти 210 вариантов вручную [что-то вроде if(ABC) -> NUM1+=5+6+7, if (ABD) -> NUM1+=5+6+9 и тд].
Так же было бы желательно наложить это на предыдущие шаги, которые более простые. А именно 2-8+ этажей в каждом только 1 слот и 2-7 возможных буквы на слот (этот вариант примерно представляю как сделать самостоятельно).
UPD: Добавил небольшой упрощенный пример программы и ее вывода. Первый раз тут так что заранее извиняюсь. Программа берет поочередно на каждом этаже, что представлена на схеме, одну из 2х комбинаций, получая условные (1-2-3), потом (1-2-4) и так далее через цикл, генерируя все 8 возможных вариантов и все значения для каждого из вариантов. Это у меня работает. Я просто не знаю как сделать так, чтобы на конечном этапе она еще и выбирала 3 буквы из 7 возможных и дополнительно накладывалась на уже сгенерированные варианты, к примеру, пару вариантов будет :
[1-2-3][ABC]
[1-2-3][ABD]
[1-2-4][ACE]
И так далее. т.е. таких вариантов будет ОЧЕНЬ много. И в каждом случае будет разное значение переменной NUM, и я как хочу найти наибольшее значение среди ВСЕХ вариантов. Составлял вопрос вроде как спокойно и осмысленно, но не знаю как выразиться еще более понятно.
#include <iostream>
#include <string>
int main()
{
setlocale(LC_ALL, "Russian");
using namespace std;
float NUM = 1;
int i = 0;
int j = 0;
int k = 0;
for (i = 0; i < 2; i++)
{
switch (i)
{
case 0:
NUM += 5;
break;
case 1:
NUM = NUM * 2;
break;
}
for (j = 0; j < 2; j++)
{
switch (j)
{
case 0:
NUM += 10;
break;
case 1:
NUM = NUM * 1.5;
break;
}
for (k = 0; k < 2; k++)
{
switch (k)
{
case 0:
NUM += 2;
break;
case 1:
NUM = NUM * 4;
break;
}
cout << "\nNUM = " << NUM;
switch (k)
{
case 0:
NUM -= 2;
break;
case 1:
NUM = NUM / 4;
break;
}
}
switch (j)
{
case 0:
NUM -= 10;
break;
case 1:
NUM = NUM / 1.5;
break;
}
}
switch (i)
{
case 0:
NUM -= 5;
break;
case 1:
NUM = NUM / 2;
break;
}
}
}
Ответы (3 шт):
Код по генерации всех комбинаций по 3 буквы из 7.
#include <iostream>
using namespace std;
int main()
{
const char* str = "ABCDEFG";
const int strsize = 7;
int count = 1;
for(int i=0; i < strsize-2; i++)
for(int j=i+1; j < strsize-1; j++)
for(int k=j+1; k<strsize; k++ )
{
cout << count << "\t" << str[i] << str[j] << str[k] << "\n";
count++;
}
return 0;
}
Дальше вам нужна функция, которая в зависимости от буквы (индекса) делает определенную операцию. Ну что-то вроде:
int foo(int num, int operation)
{
switch(operation)
{
case 0: return num + 1;
case 1: return num + 1;
case 2: return num + 1;
case 3: return num + 1;
case 4: return num + 1;
case 5: return num + 1;
case 6: return num + 1;
};
}
Добавляете в цикл, считаете результат, сразу ищете максимум и всё.
Впринципе уже законченная программа, она работает, работает правильно, но медленно, я боюсь, если накинуть на ее еще эти 35 вариантов с кубиками, то минута просчета превратится в полчаса. Может, можно как то оптимизировать код или дать ресурсов Visual Studio на системном уровне, чтоб комп гудел но ресурсы процессора/видюхи работали на просчет программы больше?
//Program Max Crit for set <Venomous Smite>
#include <iostream>
#include <string>
int main()
{
setlocale(LC_ALL, "Russian");
using namespace std;
//Base Stats (Базовые параметры, которыми обладает персонаж)
const float Base_Power = 4234;
const float Base_Power_multiplier = 1.41;
const float Base_Mana = 29160; // Если используем ультимативную способность - добавить к этому значению +10к
const float Base_Mana_multiplier = 1.02;
const float Base_penetr = 1487;
const float Base_crit_power = 1.7;
const float Base_minefield_dmg_multiplier = 1.125;
const float Base_rune_dmg_multiplier = 1.125;
const float Base_trap_dmg_multiplier = 1.225;
const float Base_Enemy_resist = 33000;
// const float Base_crit_chance = 0,3; // Не используется в данной программе
//Skill Coefficients (Коэффициенты умений, скалирующие силу/ману в урон.)
const float minefield_power_coef = 1.26053;
const float minefield_mana_coef = 0.119984;
const float rune_power_coef = 1.08501;
const float rune_mana_coef = 0.103219;
const float trap_power_coef = 0.542534;
const float trap_mana_coef = 0.051638;
//Variants (Возможные варианты на каждом этапе)
string Race[3] = { "<HighElf>","<WoodElf>","<Khajit>" };
string Mundus[3] = { "<Warrior>","<Lover>","<Shadow>" };
string Weapon[7] = { "<Sword-Sword>","<Mace-Mace>","<Axe-Axe>","<Sword-Mace>","<Sword-Axe>","<Mace-Axe>","<FireStaff>" };
string Trait[3] = { "<Nirn-Nirn>","<Sharpened-Sharpened>","<Nirn-Sharpened>" };
string Shoulders[3] = { "<2M>","<1M1L>","<2L>" };
string Skill[3] = { "<2Power>","<1Power1SorcMana>","<2Mana>" };
//Calculations (Вычисления)
float Power = Base_Power;
float Power_multiplier = Base_Power_multiplier;
float Mana = Base_Mana;
float Mana_multiplier = Base_Mana_multiplier;
float penetr = Base_penetr;
float crit_power = Base_crit_power;
float minefield_dmg_multiplier = Base_minefield_dmg_multiplier;
float rune_dmg_multiplier = Base_rune_dmg_multiplier;
float trap_dmg_multiplier = Base_trap_dmg_multiplier;
float Enemy_resist = Base_Enemy_resist;
int iRace = 0; //
int iMundus = 0; //
int iWeapon = 0; //
int iTrait = 0; // Блок счетчиков-переменных i,j,k и тд. для каждого цикла
int iSkill = 0; //
int Number = 0; //
int iShoulders = 0; //
float Winner2x = 0; // 2 Переменные для финального счета умений (Мина + руна) и (Мина + руна + ловушка)
float Winner3x = 0; //
string WinnerRace2 = { "0" }; //
string WinnerMundus2 = { "0" }; //
string WinnerWeapon2 = { "0" }; //
string WinnerTrait2 = { "0" }; //
string WinnerShoulders2 = { "0" }; //
string WinnerSkill2 = { "0" }; //
// Блок инициализаций этапов для вывода комбинаций в конце программы
string WinnerRace3 = { "0" }; //
string WinnerMundus3 = { "0" }; //
string WinnerWeapon3 = { "0" }; //
string WinnerTrait3 = { "0" }; //
string WinnerShoulders3 = { "0" }; //
string WinnerSkill3 = { "0" }; //
//Сам цикл, перебирающий все возможные варианты и выводящий на экран конечный результат и комбинацию, приведшую к этому результату
for (iRace = 0; iRace < 3; iRace++)
{
switch (iRace)
{
case 0: //High elf: +258 power, +2000 mana
Power += 258;
Mana += 2000;
break;
case 1: //Wood elf: +950 penetration, +2000 mana
penetr += 950;
Mana += 2000;
break;
case 2: //Khajit: +915 mana, +12% crit power
Mana += 915;
crit_power += 0.12;
break;
}
for (iMundus = 0; iMundus < 3; iMundus++)
{
switch (iMundus)
{
case 0: // Warrior: +389 power
Power += 389;
break;
case 1: // Lover: +4489 penetration
penetr += 4489;
break;
case 2: // Shadow : +18% crit power
crit_power += 0.18;
break;
}
for (iWeapon = 0; iWeapon < 7; iWeapon++)
{
switch (iWeapon) //(any dual weapon combination +80power) Each sword +142 power, Each mace +1650 penetration, Each axe +6% crit power, firestaff +10% dmg to minefield
{
case 0:
Power += 364;//284 + 80 (passive)
break;
case 1:
penetr += 3300;
Power += 80;
break;
case 2:
crit_power += 0.12;
Power += 80;
break;
case 3:
Power += 222; //142 + 80 (passive)
penetr += 1650;
break;
case 4:
Power += 222; //142 + 80 (passive)
crit_power += 0.06;
break;
case 5:
penetr += 1650;
crit_power += 0.06;
Power += 80;
break;
case 6:
minefield_dmg_multiplier += 0.1;
break;
}
for (iTrait = 0; iTrait < 3; iTrait++)
{
switch (iTrait) //2 gem for 2 weapons (staff 2-handed, 1 gem on 2 hands)
{
case 0: //2 nirn gem + 235 power
Power += 235;
break;
case 1: //2 sharpened gem + 3276 penetration
penetr += 3276;
break;
case 2: //1 nirn + 1 sharpened gem, +200 power +1638 penetration
Power += 200;
penetr += 1638;
break;
}
for (iShoulders = 0; iShoulders < 3; iShoulders++)
{
switch (iShoulders)
{
case 0: //2 medium shoulder +4% power, +4% crit power
Power_multiplier += 0.04;
crit_power += 0.04;
break;
case 1: //1 medium +2% power + 2% crit power, 1 light +939 penetration. (if have light = +2% mana)
Power_multiplier += 0.02;
crit_power += 0.02;
penetr += 939;
Mana_multiplier += 0.02;
break;
case 2: //2 light +1878 penetration, (if have light = +2% mana)
penetr += 1878;
Mana_multiplier += 0.02;
break;
}
for (iSkill = 0; iSkill < 3; iSkill++)
{
switch (iSkill)
{
case 0: //2 power skills on bar = +6% power
Power_multiplier += 0.06;
break;
case 1: //1 power 1 mana skills on bar = +5% power +8% mana
Power_multiplier += 0.05;
Mana_multiplier += 0.08;
break;
case 2: //2 mana skills on bar = +2% power + 15% mana
Power_multiplier += 0.02;
Mana_multiplier += 0.15;
break;
}
//33k resist = -50% dmg taken of target
Enemy_resist = Base_Enemy_resist - penetr;
float Clear_Minefield_dmg = (((Power * Power_multiplier * minefield_power_coef) + (Mana * Mana_multiplier * minefield_mana_coef)) * minefield_dmg_multiplier * crit_power);
float Clear_Rune_dmg = (((Power * Power_multiplier * rune_power_coef) + (Mana * Mana_multiplier * rune_mana_coef)) * rune_dmg_multiplier * crit_power);
float Clear_Trap_dmg = (((Power * Power_multiplier * trap_power_coef) + (Mana * Mana_multiplier * trap_mana_coef)) * trap_dmg_multiplier * crit_power);
float Minefield_dmg = Clear_Minefield_dmg * (1 - (Enemy_resist / 66000));
float Rune_dmg = Clear_Rune_dmg * (1 - (Enemy_resist / 66000));
float Trap_dmg = Clear_Trap_dmg * (1 - (Enemy_resist / 66000));
if ((Minefield_dmg + Rune_dmg) > Winner2x)
{
WinnerRace2 = Race[iRace];
WinnerMundus2 = Mundus[iMundus];
WinnerWeapon2 = Weapon[iWeapon];
WinnerTrait2 = Trait[iTrait];
WinnerShoulders2 = Shoulders[iShoulders];
WinnerSkill2 = Skill[iSkill];
Winner2x = Minefield_dmg + Rune_dmg;
}
if ((Minefield_dmg + Rune_dmg + Trap_dmg) > Winner3x)
{
//string Winner3T[6] = { Race[iRace],Mundus[iMundus],Weapon[iWeapon],Trait[iTrait],Shoulders[iShoulders],Skill[iSkill] };
//[ПРОБЛЕМА] Пытался запихнуть вместо следующих 6 строк ту, что выше, пишет мол ошибка с операндом "=". Хотел чтобы каждую комбинацию записало в массив и вывело в конце, но не дает, пришлось сделать в виде 6-ти отдельных переменных.
WinnerRace3 = Race[iRace];
WinnerMundus3 = Mundus[iMundus];
WinnerWeapon3 = Weapon[iWeapon];
WinnerTrait3 = Trait[iTrait];
WinnerShoulders3 = Shoulders[iShoulders];
WinnerSkill3 = Skill[iSkill];
Winner3x = Minefield_dmg + Rune_dmg + Trap_dmg;
}
cout << "\nУрон минного поля = " << Clear_Minefield_dmg << " | Урон руны = " << Clear_Rune_dmg << " | Урон ловушки = " << Clear_Trap_dmg << " | Результирующий чистый урон = " << Clear_Minefield_dmg + Clear_Rune_dmg + Clear_Trap_dmg << "\nРезультирующий урон по цели = " << Minefield_dmg + Rune_dmg + Trap_dmg << " При сопротивлении в: " << Enemy_resist / 660 << "%\nКомбинация: " << Race[iRace] << Mundus[iMundus] << Weapon[iWeapon] << Trait[iTrait] << Shoulders[iShoulders] << Skill[iSkill];
cout << "\nСила: <" << Power << "> Множитель силы: <" << Power_multiplier << "> Мана: <" << Mana << "> Множитель маны: <" << Mana_multiplier << "> Пробитие: <" << penetr << "> Критический урон: <" << crit_power << ">\nМножитель урона мины: <" << minefield_dmg_multiplier << "> Множитель урона руны: <" << rune_dmg_multiplier << "> Множитель урона ловушки: <" << trap_dmg_multiplier << ">\n"; // Отладочная команда, можно закоментировать.
Number++;
//[ПРОБЛЕМА] Следующие свитчи вплоть до конца цикла, это возвращение к тем параметрам, что были ДО начала цикла. Мы взяли кубик, посчитали его значение, положили обратно. Сделал отнятием тех значений что прибавили, хотя не знаю, вероятно, можно сделать проще и умнее.
switch (iSkill)
{
case 0:
Power_multiplier -= 0.06;
break;
case 1:
Power_multiplier -= 0.05;
Mana_multiplier -= 0.08;
break;
case 2:
Power_multiplier -= 0.02;
Mana_multiplier -= 0.15;
break;
}
}
switch (iShoulders)
{
case 0:
Power_multiplier -= 0.04;
crit_power -= 0.04;
break;
case 1:
Power_multiplier -= 0.02;
crit_power -= 0.02;
penetr -= 939;
Mana_multiplier -= 0.02;
break;
case 2:
Mana_multiplier -= 0.02;
penetr -= 1878;
break;
}
}
switch (iTrait)
{
case 0:
Power -= 235;
break;
case 1:
penetr -= 3276;
break;
case 2:
Power -= 200;
penetr -= 1638;
break;
}
}
switch (iWeapon)
{
case 0:
Power -= 364;//(-80 passive)
break;
case 1:
penetr -= 3300;
Power -= 80;
break;
case 2:
crit_power -= 0.12;
Power -= 80;
break;
case 3:
Power -= 222;//(-80 passive)
penetr -= 1650;
break;
case 4:
Power -= 222;//(-80 passive)
crit_power -= 0.06;
break;
case 5:
penetr -= 1650;
crit_power -= 0.06;
Power -= 80;
break;
case 6:
minefield_dmg_multiplier -= 0.1;
break;
}
}
switch (iMundus)
{
case 0:
Power -= 389;
break;
case 1:
penetr -= 4489;
break;
case 2:
crit_power -= 0.18;
break;
}
}
switch (iRace)
{
case 0:
Power -= 258;
Mana -= 2000;
break;
case 1:
penetr -= 950;
Mana -= 2000;
break;
case 2:
Mana -= 915;
crit_power -= 0.12;
break;
}
}
cout << "\n--------------------------------------------------------------------------------------------------------------------\nПобедитель [Минное поле + Руна]: " << WinnerRace2 << WinnerMundus2 << WinnerWeapon2 << WinnerTrait2 << WinnerShoulders2 << WinnerSkill2 << " При счете: " << Winner2x << "\nПобедитель [Минное поле + Руна + Капкан] = " << WinnerRace3 << WinnerMundus3 << WinnerWeapon3 << WinnerTrait3 << WinnerShoulders3 << WinnerSkill3 << "При счете: " << Winner3x << "\n\nКоличество сгенерированных вариантов:" << Number << "\n--------------------------------------------------------------------------------------------------------------------\n";
}
Можно немного упростить, заодно и ускорить код. Сначала сделать циклы, а потом в последнем делать все расчеты. Не придется откатывать значения на предыдущие. Переменные будут локальными - лучше соптимизируются.
for (iRace = 0; iRace < 3; iRace++)
for (iMundus = 0; iMundus < 3; iMundus++)
for (iWeapon = 0; iWeapon < 7; iWeapon++)
for (iTrait = 0; iTrait < 3; iTrait++)
for (iShoulders = 0; iShoulders < 3; iShoulders++)
for (iSkill = 0; iSkill < 3; iSkill++)
{ // инициализация переменных
double Power = Base_Power;
...
switch (iRace) {}
switch (iMundus) {}
switch (iWeapon) {}
switch (iTrait) {}
switch (iShoulders) {}
switch (iSkill) {}
// расчет
Enemy_resist = Base_Enemy_resist - penetr;
float Clear_Minefield_dmg =
...
}
