fork download
  1. /* Ну-с, начнём, помолясь. Постановка задачи следующая:
  2. Имеется сорка 71-го левела, все поинты до сего момента были вложены в молнии,
  3. за исключением одного в Warmth. Хочется иметь какой-нибудь ещё источник урона,
  4. помимо молний, чтобы не очень страдать от иммунов, но при этом
  5. не хочется слишком сильно снижать урон от молний, да и не так уж и много
  6. осталось поинтов - всего 31. Поэтому, задача - вложить поинты максимально
  7. эффективным способом, чтобы получить ощутимый урон, потратив как можно меньше.
  8.  
  9. Как объект исследования был выбран спелл Fire Wall, который, несмотря на своё
  10. сомнительное удобство, этим требованиям удовлетворяет. Расчёт базируется на тех
  11. предметах, которые у меня есть в данный момент, кроме щита с рунвордом Spirit,
  12. которого пока нет, но должен появиться в обозримом будущем.
  13.  
  14. Теперь о механике сорки. Огненные и электрические ветки работают похожим образом.
  15. Итоговый урон спелла вычисляется по следующей простой формуле:
  16.  
  17. Damage = Base_factor * Synergy_factor * Mastery_factor.
  18.  
  19. Base_factor - базовый урон, индивидуален для каждого спелла и зависит от его уровня.
  20.  
  21. Synergy_factor - множитель, зависящий от прокачанных синергий - всех, какие есть
  22. у данного спелла. Между собой синергии стакаются аддитивно. К примеру,
  23. у Firewall синергии две - Inferno (1% за уровень) и Warmth (4% за уровень). Если
  24. в Inferno, скажем, вложено 4 очка, а в warmth - 2, то множитель синергий
  25. будет равен 1 + 4 * 0,01 + 2 * 0,04 = 1,12. Inferno - проходной скилл (один из двух),
  26. так что нам придётся взять его хотя бы на единицу, но больше туда вкладываться
  27. смысла нет.
  28. Неочевидный момент: здесь имеет значение именно количество скиллпоинтов,
  29. вложенных в синергию, а не её уровень. Иными словами, +skills с предметов
  30. не учитывается.
  31.  
  32. Mastery_factor - соответственно, множитель, зависящий от уровня соответствующей
  33. мастери. Для ледяной ветки этот множитель отсутствует - колд мастери работает
  34. по-другому, и вместо увеличения номинального урона снижает резисты цели. Для огня же
  35. он вычисляется по следующей формуле:
  36. Mastery_factor = 1,30 + 0,07 * (mastery_level - 1) = 1,23 + 0,07*mastery_level;
  37. Если мастери не взята совсем, множитель, очевидно, равен единице.
  38.  
  39. Эта программа строит таблицу, описывающую оптимальную раскачку для любого количества
  40. скиллпоинтов, которые мы хотели бы вложить.
  41.  
  42. В принципе, задача допускает аналитическое решение, но оно было бы довольно
  43. громоздким из-за относительно сложной зависимости базового урона от уровня спелла
  44. В то же время, число параметров невелико, так что можно действовать и в лоб.
  45. Всего нужно перебрать что-то около 8000 вариантов, и, соответственно,
  46. выполнить 8000 сравнений и вдвое больше умножений.
  47.  
  48. ==========================
  49.  
  50. Легенда:
  51.  
  52. T - общее количество вложенных скиллпоинтов (от слова Total)
  53. B - оптимальный уровень базового спелла (в нашем случае - Fire Wall)
  54. S - оптимальный уровень синергии (в нашем случае - Warmth)
  55. M - оптимальный уровень мастери
  56. D - итоговый урон
  57.  
  58. Все уровни - без учёта +skills
  59. */
  60.  
  61.  
  62. #include <stdio.h>
  63.  
  64. // Маленькая вспомогательная функция. Наверняка есть в какой-нибудь библиотеке,
  65. // но мне лень искать
  66.  
  67. int min (int a, int b)
  68. {
  69. return (a<b)?a:b;
  70. }
  71.  
  72. // Функция, вычисляющая cредний базовый ДПС Fire Wall,
  73. // в зависимости от уровня навыка. Определена экспериментально.
  74.  
  75. int base(int level)
  76. {
  77. if (level == 0)
  78. {
  79. return 0;
  80. }
  81. else if(level <= 8)
  82. {
  83. return 82 + 42 * (level - 1);
  84. }
  85. else if(level <= 16)
  86. {
  87. return 377 + 65.4 * (level - 8);
  88. }
  89. else
  90. {
  91. return 900 + 98.47 * (level - 16);
  92. }
  93. }
  94.  
  95. int main(void) {
  96.  
  97. // Тут у нас параметры задачи - насколько соответствующие скиллы уже
  98. // прокачаны, бонусы с вещей и число скиллпоинтов в наличии.
  99.  
  100. const int base_invested = 0, synergy_invested = 1, mastery_invested = 0,
  101. base_plus = 0, mastery_plus = 1, all_plus = 6,
  102. skillpoints_available = 29;
  103.  
  104. // Определяем переменные. Чтобы не вычислять множители каждый раз,
  105. // мы их вычислим заранее и поместим в массивы.
  106.  
  107. int i, base_factor[21];
  108. double synergy_factor[21], mastery_factor[21];
  109.  
  110. int base_lim = 20 - base_invested;
  111. int mastery_lim = 20 - mastery_invested;
  112. int synergy_lim = 20 - synergy_invested;
  113.  
  114. // Дальше идут три почти одинаковых цикла, заполняющих массивы.
  115.  
  116. for(i = 0; i <= base_lim; i++)
  117. {
  118. int effective; // Эффективный уровень скилла
  119. if(i + base_plus + base_invested == 0)
  120. {
  121. // Если скилл не взят и на него нет прямых плюсов, его уровень равен нулю
  122. effective = 0;
  123. }
  124. else
  125. {
  126. // Иначе - сумма вложенного сейчас, вложенного ранее, и плюсов с предметов
  127. effective = i + base_invested + base_plus + all_plus;
  128. }
  129. base_factor[i] = base(effective);
  130. }
  131.  
  132.  
  133. for(i = 0; i <= synergy_lim; i++)
  134. {
  135. // Всё то же самое - по модулю того, что плюсы не учитываются
  136. int effective;
  137. if(i + synergy_invested == 0)
  138. {
  139. effective = 0;
  140. }
  141. else
  142. {
  143. effective = i + synergy_invested;
  144. }
  145. synergy_factor[i] = 1.01 + 0.04 * effective;
  146. }
  147.  
  148. for(i = 0; i <= mastery_lim; i++)
  149. {
  150. double effective;
  151. if(i + mastery_plus + mastery_invested == 0)
  152. {
  153. effective = 1.0;
  154. }
  155. else
  156. {
  157. effective = 1.23 + 0.07*(i + mastery_invested + mastery_plus + all_plus);
  158. }
  159. mastery_factor[i] = effective;
  160. }
  161.  
  162. // Теперь начинаем строить таблицу. Для начала выведем её шапку (легенда выше)
  163. printf("T\tB\tS\tM\tD\n");
  164.  
  165. int skillpoints; // скиллпоинты, вложенные в урон Fire Wall
  166.  
  167. // Количество строк в таблице. Ясно, что их не больше, чем доступно скиллпоинтов,
  168. // и если скиллпоинты уже некуда вкладывать, то дальше продолжать бессмысленно
  169. int table_rows = min(base_lim+synergy_lim+mastery_lim, skillpoints_available);
  170.  
  171. for(skillpoints = 1; skillpoints <= table_rows; skillpoints++)
  172. {
  173. int base_level, synergy_level, mastery_level,
  174. base_optimal, synergy_optimal, mastery_optimal;
  175. double damage, damage_optimal = 0;
  176.  
  177. // внешний цикл перебирает базу. Нельзя вложить больше
  178. // скиллпоинтов, чем есть, и нельзя поднять левел выше 20.
  179. int outer_lim = min(base_lim, skillpoints);
  180.  
  181. for(base_level = 0; base_level <= outer_lim; base_level++)
  182. {
  183. // внутренний цикл перебирает значения синергии
  184. // всё то же самое, только доступных скиллпоинтов уже меньше -
  185. // часть ушла в базовый спелл
  186. int inner_lim = min(synergy_lim, skillpoints - base_level);
  187.  
  188. for(synergy_level = 0; synergy_level <= inner_lim; synergy_level++)
  189. {
  190. // в мастери идёт всё, что осталось
  191. mastery_level = skillpoints - base_level - synergy_level;
  192.  
  193. // если уровень мастери получается больше 20 - это невозможная
  194. // ситуация, пропускаем её
  195. if (mastery_level > mastery_lim) continue;
  196.  
  197. // вычисляем урон при данном распределении скиллпоинтов
  198.  
  199. damage = base_factor[base_level] * synergy_factor[synergy_level] *
  200. mastery_factor[mastery_level];
  201.  
  202. // стандартные действия для поиска максимума:
  203. // если текущее значение больше запомненного - запоминаем текущее.
  204.  
  205. if(damage > damage_optimal)
  206. {
  207. base_optimal = base_level;
  208. synergy_optimal = synergy_level;
  209. mastery_optimal = mastery_level;
  210. damage_optimal = damage;
  211. }
  212. }
  213. }
  214.  
  215. // вывод строки таблицы
  216.  
  217. printf("%d\t%d\t%d\t%d\t%lf\n", skillpoints, base_optimal+base_invested,
  218. synergy_optimal+synergy_invested, mastery_optimal+mastery_invested,
  219. damage);
  220. }
  221. return 0;
  222. }
Success #stdin #stdout 0s 2112KB
stdin
Standard input is empty
stdout
T	B	S	M	D
1	1	1	0	603.204000
2	2	1	0	679.056000
3	3	1	0	798.252000
4	4	1	0	915.642000
5	5	1	0	1034.838000
6	6	1	0	1152.228000
7	7	1	0	1271.424000
8	8	1	0	1388.814000
9	9	1	0	1506.204000
10	10	1	0	1625.400000
11	11	1	0	1802.388000
12	12	1	0	1979.376000
13	13	1	0	2158.170000
14	14	1	0	2335.158000
15	15	1	0	2513.952000
16	16	1	0	2690.940000
17	17	1	0	2869.734000
18	18	1	0	3046.722000
19	19	1	0	3225.516000
20	20	1	0	3402.504000
21	20	1	1	3532.123200
22	20	1	2	3661.742400
23	20	2	2	3791.361600
24	20	2	3	3920.980800
25	20	3	3	4050.600000
26	20	3	4	4180.219200
27	20	4	4	4309.838400
28	20	4	5	4439.457600
29	20	5	5	4569.076800