Advertisement
magneto903

math_marathon_2020_task_3

Dec 6th, 2020 (edited)
561
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 11.11 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.   <title>math marathon 2020 task 3</title>
  5. </head>
  6. <body>
  7.  
  8.  
  9. <canvas id="canvas" width=10000 height=10000 >
  10. </canvas>
  11. <script>
  12.   var ctx = document.getElementById('canvas').getContext('2d')
  13.  
  14.   var circle = function (x, y, radius, color, fillCircle=true) {
  15.   ctx.beginPath();
  16.   ctx.arc(x, y, radius, 0, Math.PI * 2, false);
  17.   if (fillCircle) {
  18.     ctx.fillStyle = color;
  19.     ctx.fill();
  20.   } else {
  21.     ctx.strokeStyle = color;
  22.     ctx.stroke();
  23.   }
  24. };
  25.  
  26.  
  27.  
  28.  
  29. /**
  30.  * Возвращает строку длины n состоящую из символов s
  31.  * Имеет логарифмическую сложность.
  32.  *
  33.  * @param   {String} s
  34.  * @returns {String}
  35.  */
  36. function repeat(s, n) {
  37.     let ans = s;
  38.     let len = 1;
  39.    
  40.     while (n / len > 1) {
  41.         ans += ans;
  42.         n -= len;
  43.         len *= 2;
  44.     }
  45.     if (n > 1) {
  46.         ans += ans.substr(0, n - 1);
  47.     }
  48.     return ans;
  49. }
  50.  
  51. function shift(line, move){
  52.     move = -move % line.length;
  53.     if (move == 0) {
  54.         return line;
  55.     }
  56.  
  57.     move = (move < 0) ? line.length + move : move;
  58.    var result = [],
  59.        index;
  60.    for (var i = 0; i < line.length; i++) {
  61.        index = (i + move) % line.length;
  62.        result[i] = line[index];
  63.    }
  64.    return result.join('');
  65. }
  66.  
  67. function reverseString(str) {
  68.  
  69.  return str.split("").reverse().join("");
  70.  
  71. }
  72.  
  73. String.prototype.replaceAt=function(index, replacement) {
  74.    return this.substr(0, index+1
  75.      ) + replacement+ this.substr(index + replacement.length);
  76. }
  77.  
  78.  
  79. // тех. параметры
  80.  
  81. r1 = 25 // радиус внутреннего кольца
  82. r2 = 50 // радиус внешнего кольца
  83.  
  84. // координаты центра призмы
  85. center_x = 200
  86. center_y = 200
  87.  
  88. // сгенерируем граф: N-призму
  89. N=5
  90.  
  91. // маленькие числа - внутреннее кольцо
  92. // большие числа - внешнее кольцо
  93.  
  94. // коориданты точек
  95. var points = {}
  96.  
  97. // отношения между точками
  98. var graph = {}
  99.  
  100. // генерация внутреннего и внешнего кольца
  101. var step = Math.PI*2/N
  102.  
  103. for (var i=0; i < N; i++) {
  104.     // направление луча
  105.     var angle = i*step
  106.  
  107.  // точка внутреннего кольца
  108.  var x1 = center_x + Math.cos(angle)*r1;
  109.  var y1 = center_y + Math.sin(angle)*r1;
  110.  points[String(i)] = {"x": x1, "y": y1};
  111.  
  112.  // точка внешнего кольца
  113.  var x2 = center_x + Math.cos(angle)*r2;
  114.  var y2 = center_y + Math.sin(angle)*r2;
  115.  points[String(i+N)] = {"x": x2, "y": y2};
  116.  
  117.  // добавим их в граф
  118.  graph[String(i)] = []
  119.  graph[String(i+N)] = []
  120. }
  121.  
  122. //print(graph)
  123.  
  124. // построим рёбра графа
  125. // проход по обоим кольцам одновременно
  126. for (var i=0; i < N-1; i++) {
  127.  // ребро между кольцами
  128.  graph[String(i)].push(String(i+N))
  129.  graph[String(i+N)].push(String(i))
  130.  
  131.  // ребро-сегмент внутреннего кольца
  132.  graph[String(i)].push(String(i+1))
  133.  graph[String(i+1)].push(String(i))
  134.  
  135.  // ребро-сегмент внешнего кольца
  136.  graph[String(i+N)].push(String(i+N+1))
  137.  graph[String(i+N+1)].push(String(i+N))
  138. }
  139.  
  140. // последнее ребро
  141. b = 0
  142. e = N-1
  143.  
  144. graph[String(b)].push(String(e))
  145. graph[String(e)].push(String(b))
  146.  
  147. graph[String(e)].push(String(e+N))
  148. graph[String(e+N)].push(String(e))
  149.  
  150. graph[String(b+N)].push(String(e+N))
  151. graph[String(e+N)].push(String(b+N))
  152.  
  153. right_ways = []
  154. unique_right_ways = []
  155. super_unique_right_ways = []
  156.  
  157. var time_1 = 0
  158. var time_2 = 0
  159. var time_3 = 0
  160.  
  161. var s_time = performance.now()
  162.  
  163. // кодирование раскраски графа будет таким:
  164. // 0 - белый, 1 - черный, нумерация вершин с нуля
  165. // пример раскраски: 010101 (первая, третья и пятая - белые, остальные - черные)
  166.  
  167. // перебираем все раскраски
  168. for (var i=0; i < Math.pow(2, N*2)+1; i++) {
  169.  var good = true
  170.  // получаем номер текущей раскраски
  171.  var painting = (i).toString(2)
  172.  
  173.  if (painting.length < N*2) {
  174.    painting = repeat('0', (N*2 - painting.length)) + painting
  175.  }
  176.  // проходим по каждой вершине
  177.  for (var j=0; j < painting.length; j++) {
  178.    vex_color = painting[j]
  179.    other_colors = new Set() // цвета соседей
  180.  
  181.  
  182.    // пройдём по её соседям
  183.    for (var k in graph[String(j)]) {
  184.      // цвет соседа
  185.      other_color = painting[Number(graph[String(j)][k])]
  186.      other_colors.add(other_color)
  187.    }
  188.    if (other_colors.size == 1) {
  189.      good = false
  190.      break
  191.    }
  192.  }
  193.  
  194.  //if (painting == '111000') {
  195.    //console.log(painting, good)
  196.  //}
  197.  
  198.  if (good) {
  199.    right_ways.push(painting)
  200.  }
  201. }
  202.  
  203. time_1= performance.now() - s_time
  204.  
  205. var get_rotations = function(way) {
  206.  var rotated_ways = []
  207.  // идём по первой половине
  208.  for (var i=0; i < way.length/2; i++) {
  209.    rotated_way = way.slice(i,N) + way.slice(0,i) + way.slice(i+N,N+N) + way.slice(N,i+N)
  210.    rotated_ways.push(rotated_way)
  211.  }
  212.  
  213.  return rotated_ways
  214. }
  215.  
  216. var get_symmetricals = function(way) {
  217.  symmetrical_ways = []
  218.  // возвращает симметрию по каждой из осей
  219.  // идём по вершинам - выбираем ось
  220.  // если нечетное, то идём по всем осям
  221.  if ( (way.length/2) % 2 == 1 ) {
  222.    for (var i=0; i < way.length/2; i++) {
  223.      // сдвинем так, чтобы ось была по-середине
  224.  
  225.      centered_way_1 = shift(way.slice(0, way.length/2), Math.floor(way.length/2)-i)
  226.      centered_way_2 = shift(way.slice(way.length/2, way.length), Math.floor(way.length/2)-i)
  227.      symmetrical_ways.push( reverseString(centered_way_1)+reverseString(centered_way_2) )
  228.      symmetrical_ways.push(centered_way_1+centered_way_2)
  229.  
  230.    }
  231.  } else {
  232.    // ЗДЕСЬ НАДО ДОРАБОТАТЬ!!!
  233.    
  234.    for (var i=0; i < way.length/4; i++) {
  235.      // идём по половие первой половины
  236.      // четвёрки
  237.      four_1 = way.slice(0, way.length/4)
  238.      four_2 = way.slice(way.length/4, way.length/2)
  239.      four_3 = way.slice(way.length/2, way.length/4*3)
  240.      four_4 = way.slice(way.length/4*3, way.length)
  241.  
  242.     // console.log(four_1, four_2, four_3, four_4)
  243.  
  244.      // оси в каждой четвёрке
  245.      axis_1 = four_1.split('').splice(i, 1)
  246.      axis_2 = four_2.split('').splice(i, 1)
  247.      axis_3 = four_3.split('').splice(i, 1)
  248.      axis_4 = four_4.split('').splice(i, 1)
  249.  
  250.      four_1 = four_1.slice(0, i)+four_1.slice(i+1, four_1.length)
  251.      four_2 = four_2.slice(0, i)+four_2.slice(i+1, four_2.length)
  252.      four_3 = four_3.slice(0, i)+four_3.slice(i+1, four_3.length)
  253.      four_4 = four_4.slice(0, i)+four_4.slice(i+1, four_4.length)
  254.  
  255.      symmetrical_ways.push( four_1.replaceAt(i-1, axis_1) + four_2.replaceAt(i-1, axis_2) + four_3.replaceAt(i-1, axis_3) + four_4.replaceAt(i-1, axis_4) )
  256.  
  257.      symmetrical_ways.push( reverseString(four_1+four_2).replaceAt(i-1, axis_1).replaceAt(i+way.length/4-1, axis_2) + reverseString(four_3+four_4).replaceAt(i-1, axis_3).replaceAt(i+way.length/4-1, axis_4))
  258.  
  259.  
  260.    }
  261.  }
  262.  
  263.  return symmetrical_ways
  264. }
  265.  
  266. var draw_way = function(way, x, y) {
  267.  // рисуем рёбра
  268.  ctx.beginPath()
  269.  for (var i=0; i < N; i++) {
  270.    ctx.moveTo(x + Math.cos(i*step)*(r1+0), y + Math.sin(i*step)*(r1+0))
  271.    ctx.lineTo(x + Math.cos((i+1)*step)*(r1+0), y + Math.sin((i+1)*step)*(r1+0))
  272.  
  273.    ctx.moveTo(x + Math.cos(i*step)*(r2+0), y + Math.sin(i*step)*(r2+0))
  274.    ctx.lineTo(x + Math.cos((i+1)*step)*(r2+0), y + Math.sin((i+1)*step)*(r2+0))
  275.  }
  276.  
  277.  
  278.  ctx.stroke()
  279.  
  280.  // рисуем вершины
  281.  for (var i=0; i < N; i++) {
  282.    ctx.beginPath()
  283.    ctx.moveTo(x + Math.cos(i*step)*(r1+10), y + Math.sin(i*step)*(r1+10))
  284.    ctx.lineTo(x + Math.cos(i*step)*r2, y + Math.sin(i*step)*r2)
  285.    ctx.stroke()
  286.    // определяем цвет
  287.    if (way[i] == '0') {
  288.      circle(x + Math.cos(i*step)*r1, y + Math.sin(i*step)*r1, 10, 'white', true)
  289.      circle(x + Math.cos(i*step)*r1, y + Math.sin(i*step)*r1, 10, 'black', false)
  290.    } else {
  291.      circle(x + Math.cos(i*step)*r1, y + Math.sin(i*step)*r1, 10, 'white', true)
  292.      circle(x + Math.cos(i*step)*r1, y + Math.sin(i*step)*r1, 10, 'black', true)
  293.    }
  294.  
  295.    // определяем цвет
  296.    if (way[i+N] == '0') {
  297.      circle(x + Math.cos(i*step)*r2, y + Math.sin(i*step)*r2, 10, 'white', true)
  298.      circle(x + Math.cos(i*step)*r2, y + Math.sin(i*step)*r2, 10, 'black', false)
  299.    } else {
  300.      circle(x + Math.cos(i*step)*r2, y + Math.sin(i*step)*r2, 10, 'white', true)
  301.      circle(x + Math.cos(i*step)*r2, y + Math.sin(i*step)*r2, 10, 'black', true)
  302.    }
  303.  }
  304. }
  305.  
  306. var x_row = 12;
  307. var y_row = 6;
  308.  
  309. var draw_all_ways = function(ways) {
  310.  // 400 x 400
  311.  for (var i=0; i < ways.length; i++) {
  312.    // определяем позицию
  313.    x = (i % x_row)*1.5
  314.    y = Math.floor(i / x_row) * 1.5
  315.  
  316.    draw_way(ways[i], x*100+100, y*100+75)
  317.  }
  318. }
  319.  
  320. var s_time = performance.now()
  321.  
  322. for (var i in right_ways) {
  323.  // изначально считаем, что эта раскраска уникальная
  324.  var unique = true
  325.  
  326.  var way = right_ways[i]
  327.  // перебор всех вариантов поворота (перебор первой половины)
  328.  var rotated_ways = get_rotations(way)
  329.  
  330.  for (var j in rotated_ways) {
  331.  
  332.    if ( unique_right_ways.indexOf(rotated_ways[j]) != -1 ) {
  333.      unique = false
  334.      break
  335.    }
  336.  }
  337.  
  338.  if (unique) {
  339.    unique_right_ways.push(way)
  340.  }
  341. }
  342.  
  343.  
  344. time_2 = performance.now() - s_time
  345.  
  346.  
  347. var s_time = performance.now()
  348.  
  349. for (var i in unique_right_ways) {
  350.  var unique = true;
  351.  var way =  unique_right_ways[i]
  352.  var symmetrical_ways = get_symmetricals(way);
  353.  
  354.  for (var j in symmetrical_ways) {
  355.    var sym_rot_ways = get_rotations(symmetrical_ways[j])
  356.    for (var k in sym_rot_ways) {
  357.      if ( super_unique_right_ways.indexOf(sym_rot_ways[k]) != -1 ) {
  358.        unique = false
  359.        break
  360.      }
  361.    }
  362.  }
  363.  
  364.  if (unique) {
  365.    super_unique_right_ways.push(way)
  366.  }
  367. }
  368.  
  369. time_3 = performance.now() - s_time
  370.  
  371. console.log( right_ways.length )
  372. console.log(unique_right_ways.length)
  373. console.log(super_unique_right_ways.length)
  374.  
  375. console.log( time_1.toFixed(2)+'/'+time_2.toFixed(2)+'/'+time_3.toFixed(2)+' ms' )
  376.  
  377. // отрисовка командой draw_all_ways()
  378.  
  379. //draw_all_ways(super_unique_right_ways); // варианты с учетом поворота и симметрии
  380. //draw_all_ways(unique_right_ways) // варианты с учетом поворота
  381. //draw_all_ways(right_ways) // все правильные варианты, т.е. варианты без учёта поворота и симметрии
  382. //console.log(right_ways.length)
  383.  
  384. //draw_all_ways(get_symmetricals("10001011"))
  385.  
  386. </script>
  387.  
  388. </body>
  389. </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement