Advertisement
Guest User

Untitled

a guest
Feb 22nd, 2018
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //note: too slow for kattis to accept
  2.  
  3. /**
  4.  * Squares stuff
  5.  */
  6. let squaresLessOrEqualTo = function(n) {
  7.     let count = Math.floor(Math.sqrt(n));
  8.     let squares = [];
  9.     for(let i = 1; i <= count; i++) {
  10.         squares.push(i * i);
  11.     }
  12.     return squares;
  13. };
  14.  
  15. let squareSums = function(n) {
  16.     let allSquares = squaresLessOrEqualTo(n);
  17.     let sums = [];
  18.     //O(n^2), find faster way
  19.     for(let i = 0; i < allSquares.length; i++) {
  20.         for(let j = 0; j < allSquares.length; j++) {
  21.             let a = allSquares[i];
  22.             let b = allSquares[j];
  23.             if(a + b === n) sums.push([a, b]);
  24.         }
  25.     }
  26.     return sums;
  27. };
  28.  
  29. /**
  30.  * Graph stuff
  31.  */
  32. //pqueue from http://eloquentjavascript.net/1st_edition/appendix2.html
  33. function BinaryHeap(scoreFunction){
  34.   this.content = [];
  35.   this.scoreFunction = scoreFunction;
  36. }
  37.  
  38. BinaryHeap.prototype = {
  39.   push: function(element) {
  40.     // Add the new element to the end of the array.
  41.     this.content.push(element);
  42.     // Allow it to bubble up.
  43.     this.bubbleUp(this.content.length - 1);
  44.   },
  45.  
  46.   pop: function() {
  47.     // Store the first element so we can return it later.
  48.     var result = this.content[0];
  49.     // Get the element at the end of the array.
  50.     var end = this.content.pop();
  51.     // If there are any elements left, put the end element at the
  52.     // start, and let it sink down.
  53.     if (this.content.length > 0) {
  54.       this.content[0] = end;
  55.       this.sinkDown(0);
  56.     }
  57.     return result;
  58.   },
  59.  
  60.   remove: function(node) {
  61.     var length = this.content.length;
  62.     // To remove a value, we must search through the array to find
  63.     // it.
  64.     for (var i = 0; i < length; i++) {
  65.       if (this.content[i] != node) continue;
  66.       // When it is found, the process seen in 'pop' is repeated
  67.       // to fill up the hole.
  68.       var end = this.content.pop();
  69.       // If the element we popped was the one we needed to remove,
  70.       // we're done.
  71.       if (i == length - 1) break;
  72.       // Otherwise, we replace the removed element with the popped
  73.       // one, and allow it to float up or sink down as appropriate.
  74.       this.content[i] = end;
  75.       this.bubbleUp(i);
  76.       this.sinkDown(i);
  77.       break;
  78.     }
  79.   },
  80.  
  81.   size: function() {
  82.     return this.content.length;
  83.   },
  84.  
  85.   bubbleUp: function(n) {
  86.     // Fetch the element that has to be moved.
  87.     var element = this.content[n], score = this.scoreFunction(element);
  88.     // When at 0, an element can not go up any further.
  89.     while (n > 0) {
  90.       // Compute the parent element's index, and fetch it.
  91.       var parentN = Math.floor((n + 1) / 2) - 1,
  92.       parent = this.content[parentN];
  93.       // If the parent has a lesser score, things are in order and we
  94.       // are done.
  95.       if (score >= this.scoreFunction(parent))
  96.         break;
  97.  
  98.       // Otherwise, swap the parent with the current element and
  99.       // continue.
  100.       this.content[parentN] = element;
  101.       this.content[n] = parent;
  102.       n = parentN;
  103.     }
  104.   },
  105.  
  106.   sinkDown: function(n) {
  107.     // Look up the target element and its score.
  108.     var length = this.content.length,
  109.     element = this.content[n],
  110.     elemScore = this.scoreFunction(element);
  111.  
  112.     while(true) {
  113.       // Compute the indices of the child elements.
  114.       var child2N = (n + 1) * 2, child1N = child2N - 1;
  115.       // This is used to store the new position of the element,
  116.       // if any.
  117.       var swap = null;
  118.       // If the first child exists (is inside the array)...
  119.       if (child1N < length) {
  120.         // Look it up and compute its score.
  121.         var child1 = this.content[child1N],
  122.         child1Score = this.scoreFunction(child1);
  123.         // If the score is less than our element's, we need to swap.
  124.         if (child1Score < elemScore)
  125.           swap = child1N;
  126.       }
  127.       // Do the same checks for the other child.
  128.       if (child2N < length) {
  129.         var child2 = this.content[child2N],
  130.         child2Score = this.scoreFunction(child2);
  131.         if (child2Score < (swap == null ? elemScore : child1Score))
  132.           swap = child2N;
  133.       }
  134.  
  135.       // No need to swap further, we are done.
  136.       if (swap == null) break;
  137.  
  138.       // Otherwise, swap and continue.
  139.       this.content[n] = this.content[swap];
  140.       this.content[swap] = element;
  141.       n = swap;
  142.     }
  143.   }
  144. };
  145.  
  146. let createVertex = function(xPos, yPos, d) {
  147.     return {
  148.         xPos: xPos,
  149.         yPos: yPos,
  150.         d: d, //distance (in terms of number of coins) from origin
  151.         edges: []
  152.     };
  153. }
  154.  
  155. let createEdge = function(v1, v2, w) {
  156.     return {
  157.         v1: v1,
  158.         v2: v2,
  159.         w: w
  160.     };
  161. }
  162.  
  163. //recursive function.
  164. //used for creating graph only
  165. let appendChildVertices = function(vertices, edges, parentVertex, coinTypes, eMod) {
  166.     let newVertices = [];
  167.    
  168.     for(let i = 0; i < coinTypes.length; i++) {
  169.         //check to see if new vertex won't go out of bounds
  170.         let futureConvVal = parentVertex.xPos + coinTypes[i][0];
  171.         let futureInfoVal = parentVertex.yPos + coinTypes[i][1];
  172.        
  173.         if(futureConvVal <= eMod && futureInfoVal <= eMod) {
  174.            
  175.             if(!vertices[futureConvVal]) {
  176.                 vertices[futureConvVal] = [];
  177.             }
  178.            
  179.             let newEdge;
  180.             if(vertices[futureConvVal][futureInfoVal]) {
  181.                 newEdge = createEdge(parentVertex, vertices[futureConvVal][futureInfoVal], 1);
  182.                 parentVertex.edges.push(newEdge);
  183.                 edges.push(newEdge);
  184.             } else {
  185.                 let newVertex = createVertex(futureConvVal, futureInfoVal, 2000000000);
  186.                 newEdge = createEdge(parentVertex, newVertex, 1);
  187.                
  188.                 parentVertex.edges.push(newEdge);
  189.                 edges.push(newEdge);
  190.                 vertices[futureConvVal][futureInfoVal] = newVertex;
  191.                 newVertices.push(newVertex);
  192.             }
  193.         }
  194.     }
  195.    
  196.     for(let i = 0; i < newVertices.length; i++) {
  197.         appendChildVertices(vertices, edges, newVertices[i], coinTypes, eMod);
  198.     }
  199. }
  200.  
  201. let createGraph = function(coinTypes, eMod) {
  202.     //vertices are located by their x and y positions
  203.     let vertices = [];
  204.     let edges = [];
  205.    
  206.     //initial position
  207.     let originVertex = createVertex(0, 0, 0);
  208.     vertices[0] = [];
  209.     vertices[0][0] = originVertex;
  210.     appendChildVertices(vertices, edges, originVertex, coinTypes, eMod);
  211.    
  212.     return {
  213.         vertices: vertices,
  214.         edges: edges
  215.     };
  216. }
  217.  
  218. let dijkstra = function(graph) {
  219.     let q = new BinaryHeap(function(a) {return a.d});
  220.    
  221.     //push vertices into pqueue
  222.     for(let i = 0; i < graph.vertices.length; i++) {
  223.         if(graph.vertices[i]) {
  224.             for(let j = 0; j < graph.vertices[i].length; j++) {
  225.                 if(graph.vertices[i][j]) q.push(graph.vertices[i][j]);
  226.             }
  227.         }
  228.     }
  229.    
  230.     while(q.size() !== 0) {
  231.         let u = q.pop();
  232.        
  233.         for(let i = 0; i < u.edges.length; i++) {
  234.             let edge = u.edges[i];
  235.             let alt = u.d + edge.w;
  236.             if(alt < edge.v2.d) {
  237.                 edge.v2.d = alt;
  238.                 q.remove(edge.v2);
  239.                 q.push(edge.v2);
  240.             }
  241.         }
  242.     }
  243. }
  244.  
  245. /**
  246.  * Problem stuff
  247.  */
  248. let numProblems = parseInt(readline());
  249. for(let i = 0; i < numProblems; i++) {
  250.     let info = readline().split(' ');
  251.     let numCoinTypes = parseInt(info[0]);
  252.     let s = parseInt(info[1]);
  253.    
  254.     let coinTypes = [];
  255.     for(let j = 0; j < numCoinTypes; j++) {
  256.         let coinInfo = readline().split(' ');
  257.         coinTypes.push([parseInt(coinInfo[0]), parseInt(coinInfo[1])]);
  258.     }
  259.    
  260.     let graph = createGraph(coinTypes, s);
  261.    
  262.     let squareSumz = squareSums(s * s);
  263.     let squareSumsExisting = [];
  264.     for(let j = 0; j < squareSumz.length; j++) {
  265.         let sqrt1 = Math.sqrt(squareSumz[j][0]);
  266.         let sqrt2 = Math.sqrt(squareSumz[j][1]);
  267.        
  268.         if(graph.vertices[sqrt1]) {
  269.             if(graph.vertices[sqrt1][sqrt2]) {
  270.                 squareSumsExisting.push([sqrt1, sqrt2]);
  271.             }
  272.         }
  273.     }
  274.    
  275.     if(squareSumsExisting.length === 0) {
  276.         print('not possible');
  277.         if(i < numProblems - 1) readline();
  278.         continue;
  279.     }
  280.    
  281.     dijkstra(graph);
  282.    
  283.     let minCoins = 2000000000;
  284.     for(let j = 0; j < squareSumsExisting.length; j++) {
  285.         let index1 = squareSumsExisting[j][0];
  286.         let index2 = squareSumsExisting[j][1];
  287.         let d = graph.vertices[index1][index2].d;
  288.         if(d < minCoins) minCoins = d;
  289.     }
  290.    
  291.     print(minCoins);
  292.    
  293.     if(i < numProblems - 1) readline();
  294. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement