UV Problem 10270 Bigger Square Please... (Spliced square)

Source: Internet
Author: User
Tags dot net
// Bigger Square Please... (tiled square) // PC/Ultraviolet IDs: 110808/10270, Popularity: C, Success rate: high Level: 3 // Verdict: Accepted // Submission Date: 2011-09-25 // UV Run Time: 0.032 s // copyright (C) 2011, Qiu. Metaphysis # yeah dot net /// [Problem description] // Tony has a lot of square paper. The edges of these pieces of paper vary from 1 to N-1, and each type of paper contains several sheets. But he does not // satisfy. He wants a bigger piece of paper with N sides. //// You can splice existing paper into a square. For example, A square with A side length of 7 can be spliced by the following nine smaller squares // (fill the corresponding square with letters, and A indicates A square paper with A side length of 1, B Indicates the square paper with a side length of 2 //, and so on ): /// B c // a B a c // a B D // c d // c d /// there cannot be gaps in the middle of the spliced square, A piece of paper cannot exceed a square and cannot overlap with each other. In addition, Tony wants to use as little paper as possible to create a large square. Can you help him? //// [Input] // the first line of the input has a separate integer T, indicating the number of test data groups. Each group of data is a separate integer N (2 <=n <= 50 ). //// [Output] // for each group of data, output a row containing an integer K, indicating the minimum number of pieces of paper required. In the next K rows, three integers x, y, // l in each row represent the coordinates (1 <= x, y <= N) in the upper left corner of the paper and the length of the edge of the paper. //// [Sample input] // 3 // 4 // 3 // 7 // 7 /// [sample output] // 4 // 1 1 2 // 1 3 2/3 1 2/3 3 2/6/1 1 2/1 3 1/2 3 1/3 1/3 2 1 // 3 3 1 // 9 // 1 2 // 1 3 2 // 3 1 1 // 4 1 // 3 2 2 // 5 1 3/ /4 4 4 // 1 5 3 // 3 4 1 // [problem solving method] // This is one of the 10% most difficult questions in all questions on the WordPress. If the merging scheme is generated in real time, rather than pre-generated merging // scheme and then submitted, the level is indeed relatively high. The question requires that any piece of paper with a side length of 1-(N-1) be spliced into a square piece of paper with a side length of // N. The pieces of paper cannot overlap with each other, and cannot exceed the square range where the side length is N. In this case, use the join Party with the least number of pieces of paper. The upper left corner is used as the coordinate start point ), output the coordinates and length of each piece of paper in the order of coordinates and edges. /// According to the question, set the length of the square side to N. Obviously, the splicing scheme is a series of sums. This problem can be solved by backtracking. However, we have obtained a scheme to split N into the sum of the numbers of squares, which does not mean that we can splice these pieces of paper into a piece of paper with a side length of N. For example, for N = 5, you can // split it into the sum of 9 and 16, and the sum of 9 and 16 is the number of shards, however, in fact, you cannot splice a 3-side-length and a 4-side-length piece of paper into a 5-side-length piece of paper. Therefore, after generating a limit number and a scheme, you must try to place it, if this option can be placed, it indicates that this option is feasible and recorded. After recording all feasible schemes, the solution with the smallest number of pieces of paper is required. In this case, the sum of N splits/into the number of workers is one-step backtracking, and the attempt to place the splitting scheme is another one-step backtracking. This problem needs to be solved through two-step backtracking. //// Considering that two backtracing steps are required, if not fully pruning is required, the computing time will be intolerable. The discussion on this topic on the BBS of ultraviolet A (B) reflects this situation. In one step of splitting N into the sum of shards, if a splitting scheme can be generated, although it is not optimal, the total number of // shards is small and can be placed practically, using the total number of this solution as the pruning threshold will avoid a large number of invalid searches. A non-optimal solution that splits N into the number of shards // can be constructed as follows: put a piece of paper with a side length of (N-2) in the upper left corner, and then place a piece of paper with a side length of 2 on the right side and a piece of paper with a side length of 1 on the bottom, in this case, the total number of pieces of paper is: 1 + [N/2] // + [(N-2)/2] + 4, where the symbol [] indicates an integer, in this way, the total number of pieces of paper is near N, which can be used as a better pruning threshold. After finding A solution with A smaller total number of items through backtracking, you can try to place the solution. You can set up A grid array. When // fills the paper with A side length of, find whether there is A blank area with the starting coordinate (x, y) and the side length is A in the grid. If there is no such blank area, it indicates that the solution cannot be placed in reality, if this parameter can be found, locate all the starting positions and trace them one by one. Then, mark the starting position as filled, if the subsequent filling fails, the flag is revoked. You need to record the split schemes that have been generated but cannot be spliced. In the subsequently generated scheme, if the scheme is the same as the recorded scheme, you do not have to waste time searching again. //// You can find the relevant information about the problem through the network. When n mod 2 = 0 or n mod 6 = 3, there is a special solution. // For n mod 2 = 0, that is, if N is an even number, the minimum number of pieces of paper is: use 4 pieces of paper with a side length of N/2 To concatenate a square with a side length of N. When n mod 6 = 3, the placement method is similar to that of N = 3, except that the length of the corresponding paper edge is increased by the same quantity. At the same time, the merge number is similar to the 25 splicing scheme and the 5 splicing scheme. The 49 splicing scheme is similar to the 7 splicing scheme, then the number is between 2-50, you only need to find the joining method of the prime number. The network already has a prime number of 2-50 // splicing scheme and a minimum number of pieces of paper required. Using this information can significantly reduce the computing time, or even directly generate a splicing scheme before submitting it. /// Reference webpage: // http://www2.stetson.edu /~ Efriedma/mathmagic/1298.html // http://mathpuzzle.com/perkinsbestquilts.txt// http://mathworld.wolfram.com/MrsPerkinssQuilt.html#include <iostream> # include <cstring> # include <algorithm> # include <ctime> using namespace std; # ifndef DEBUG_MODE # define DEBUG_MODE // used for testing. If you submit the statement online, comment out the statement. # Endif # define NMAX 20 // maximum number of sheets required for splitting. # Define NPRIME 11 // Number of prime numbers between 10 and 50. # Define SMAX 1024 // The maximum number of unspliced splitting schemes saved. # Define PMAX 2500 // maximum number of coordinates in the grid. # Define NCELL 50 // grid edge length. Struct square // indicates the information of the spliced paper. {Int x, y; // coordinates of the paper in the grid. Int size; // The Edge length of the paper .}; Square squares [NMAX]; // record the current stitching scheme. Square best [NMAX]; // the best practical splicing solution for record search. Struct point // indicates a point in the grid. {Int x; // the abscissa of a vertex. Int y; // The ordinate of the vertex .}; // The minimum number of pieces of paper required for odd concatenation between 2-50. Int tip [24] = {6, 8, 9, 6, 11, 11, 6, 12, 13, 6, 13, 8, 6, 14, 15, 6, 8, 15, 6, 15, 16, 6, 6, 16, 9}; // The best split scheme of prime numbers between 10 and 50. The first number of items in the array indicates the prime number, and the second number indicates the number of pieces of paper required. The subsequent number is the size of the piece of paper, which is arranged in ascending order. Int trick [NPRIME] [NMAX] = {11, 11, 6, 5, 5, 4, 2, 2, 2, 2, 1, 1, 1 }, // 11 {13, 11, 7, 6, 6, 4, 3, 3, 2, 2, 2, 1, 1}, // 13 {17, 12, 9, 8, 8, 5, 4, 4, 3, 2, 2, 2, 1, 1}, // 17 {19, 13, 10, 9, 9, 5, 5, 5, 3, 2, 2, 2, 1, 1, 1}, // 19 {23, 13, 12, 11, 11, 7, 5, 5, 4, 3, 3, 2, 2, 1, 1}, // 23 {29, 14, 17, 12, 12, 9, 8, 8, 4, 4, 3, 2, 2, 2, 1, 1}, // 29 {31, 15, 16, 15, 15, 8, 8, 4, 4, 4, 2, 2, 2, 1, 1, 1}, // 3 1 {37, 15, 19, 18, 18, 11, 8, 8, 6, 5, 5, 3, 3, 2, 1, 1, 1 }, // 37 {41, 15, 23, 18, 18, 12, 11, 11, 7, 5, 4, 3, 3, 2, 2, 1, 1 }, // 41 {43, 16, 22, 21, 21, 11, 11, 6, 5, 5, 3, 3, 3, 2, 1, 1, 1}, // 43 {47, 16, 24, 23, 23, 12, 12, 12, 7, 5, 5, 4, 3, 2, 2, 2, 1, 1}, // 47}; int n; // The side length of the square to be spliced. Int smallest; // The number of pieces of paper in the current best splicing solution. Int ncount [NCELL]; // record the number of duplicate sheets in the splicing scheme. Int cell [NCELL] [NCELL]; // Mesh Used for splicing. Int backup [NCELL] [NCELL]; // records the Grid status of the actual best solution. Int ncache [NMAX]; // number of records of unspliced splitting schemes. Int cache [NMAX] [SMAX] [NMAX]; // records the splitting scheme that fails to be spliced. Bool found; // whether the actual stitching scheme of the unoptimal splitting scheme is found. Bool finished; // indicates the early end of backtracking. // Search for the coordinates in the upper left corner of the blank area with a side length of size in the grid cell. Int find (int size, point points [PMAX]) {// initially, the number of coordinates found is 0. Int npoints = 0; for (int y = 0; y <= (n-size); y ++) for (int x = 0; x <= (n-size); x ++) // The blank point is found. If (cell [y] [x] = 0) {// check whether there is a square blank area with a side length of size. Bool empty = true; for (int I = y; I <(y + size); I ++) {for (int j = x; j <(x + size ); j ++) if (cell [I] [j]! = 0) {empty = false; break;} if (! Empty) break;} // There is a blank area with a side length of size, and the START coordinate is recorded. If (empty) {points [npoints]. x = x; points [npoints]. y = y; npoints ++ ;}}return npoints ;}// output splicing scheme. Void print (square s [NMAX], int nsquares) {# ifdef DEBUG_MODEcout <"a fill solution for square with size:" <n <endl; for (int x = 0; x <n; x ++) {for (int y = 0; y <n; y ++) cout <(char) ('A' + backup [x] [y]-1) <""; cout <endl ;}# endifcout <nsquares <endl; for (int I = 0; I <nsquares; I ++) cout <s [I]. x <"" <s [I]. y <"" <s [I]. size <endl;} // try to splice a square with a side length of n according to the split Scheme blocks. Void fill (int blocks [], int ncurrent, int goal, bool display_when_find) {// all pieces of paper have been matched, indicating that the splitting scheme is feasible and output. If (ncurrent = goal) {memcpy (backup, cell, sizeof (cell); // whether to display the result. If (display_when_find) print (squares, ncurrent); elsememcpy (best, squares, sizeof (squares); finished = true;} else {int npoints; // record the number of coordinates found. Point points [PMAX]; // The starting coordinate of the record. // If not found, return. If (npoints = find (blocks [ncurrent], points) = 0) return; // location to be found one by one. For (int I = 0; I <npoints; I ++) {int x = points [I]. x; int y = points [I]. y; int s = blocks [ncurrent]; // heuristic rule: the first piece of paper is always placed in the upper left corner. If (ncurrent = 0 & (y! = 0 | x! = 0) continue; // heuristic rule: the second piece of paper is always placed in the upper right corner. If (ncurrent = 1 & (y! = 0 | x! = Blocks [0]) continue; // heuristic rule: the third piece of paper is always placed in the lower left corner. If (ncurrent = 2 & (y! = Blocks [0] | x! = 0) continue; // heuristic rule: the fourth piece of paper is always placed near the right side. If (ncurrent = 3 & x! = (N-blocks [ncurrent]) continue; // heuristic rule: the fifth piece of paper is always placed near the right side or bottom. If (ncurrent = 4 & (x! = (N-blocks [ncurrent]) & y! = (N-blocks [ncurrent]) continue; // record the current stitching method. Note that the starting point of coordinates is different, and the output must start from the starting point. Squares [ncurrent]. x = (x + 1); squares [ncurrent]. y = (y + 1); squares [ncurrent]. size = s; // the corresponding area in the tag mesh is filled. For (int gy = y; gy <(y + s); gy ++) for (int gx = x; gx <(x + s); gx ++) cell [gy] [gx] = s; // continue to match the next piece of paper. Fill (blocks, ncurrent + 1, goal, display_when_find); // whether to end backtracking. If (finished) return; // indicates that the current splicing scheme is not feasible and the grid change is revoked. For (int gy = y; gy <(y + s); gy ++) for (int gx = x; gx <(x + s); gx ++) cell [gy] [gx] = 0 ;}}// sequence rule of the sorting function. Bool cmp (int x, int y) {return x> y;} // use the minimum number of pieces of paper as the pruning threshold to search for the splitting scheme. Void cut_by_tip (int area, int blocks [NMAX], int nblocks, int goal) {// when the number of split pieces reaches the pruning threshold, but there is still an area remaining, end the backtracking. If (area> 0 & nblocks = goal) return; // when the splitting is complete, if the total number of split pieces is not the pruning threshold value, end the backtracking. If (area = 0 & nblocks! = Goal) return; // after splitting, the number of pieces of paper in the splitting scheme is the minimum. If (area = 0) {int temp [NMAX]; // note that when arrays are used as form parameters, pointers are passed, so sizeof (blocks) cannot be used) to calculate the size of the/array blocks. Memcpy (temp, blocks, NMAX * sizeof (int); // sort the paper size in ascending order. Sort (temp, temp + nblocks, cmp); // if the current splitting scheme is not found in the unspliced scheme, try splicing. Bool exist = false; for (int I = 0; I <ncache [nblocks-1]; I ++) {bool equal = true; for (int j = 0; j <nblocks; j ++) if (cache [nblocks-1] [I] [j]! = Temp [j]) {equal = false; break;} if (equal) {exist = true; break ;}// if it does not exist, try stitching. If (! Exist) {// reset the grid. Memset (cell, 0, sizeof (cell); // try to splice. Fill (temp, 0, nblocks, true); // returns if the call is successful. If (finished) return; // if the splicing fails, save it. Memcpy (cache [nblocks-1] [ncache [nblocks-1] ++], temp, sizeof (temp ));}} else {// find the maximum edges that can be split. Int up; for (int u = n-1; u> = 1; u --) if (area> = (u * u) {up = u; break ;} // heuristic rule: give priority to the pieces of paper with the size between up/2 + 1 and up. For (int r = (up/2 + 1); r <= up; r ++) {// heuristic rules: the size of the second piece of paper and the size of the first piece of paper are n. If (nblocks = 1 & (r + blocks [0])! = N) continue; // heuristic rule: the size of the third piece of paper should be the same as that of the second one. If (nblocks = 2 & r! = Blocks [1]) continue; // heuristic rule: the sum of the sizes of the fourth and fifth pieces should be the size of the first piece of paper, // The number of pieces of paper on one side of the square produced by splicing cannot exceed 3. If (nblocks = 4 & (r + blocks [3])! = Blocks [0]) continue; // records the current split. Blocks [nblocks] = r; // continue splitting. Cut_by_tip (area-(r * r), blocks, nblocks + 1, goal); // determine whether to exit in advance based on the finished flag. If (finished) return ;}}// uses the Backtracking Method to Construct the splitting scheme. The parameter is the number of areas that have not been split. Void cut_by_hard_work (int area, int blocks [NMAX], int nblocks) {// when the number of split paper pieces reaches the minimum number currently feasible, but the remaining area is still available, you do not need to try again. If (area> = 0 & nblocks> smallest) return; // For smallest, an actual splicing scheme has been found. For the same number of paper, other // splitting schemes do not have to be tried again. If (area = 0 & nblocks = smallest & found) return; // heuristic rule: there are at least two pieces of paper with a side length of 1. If (area = 0 & ncount [1] <= 1) return; // after splitting, the number of sheets of paper in the splitting scheme is smaller than the current optimal value smallest. If (area = 0) {int temp [NMAX]; // note that when arrays are used as form parameters, pointers are passed, so sizeof (blocks) cannot be used) to calculate the size of the/array blocks. Memcpy (temp, blocks, NMAX * sizeof (int); // sort the paper size in ascending order. Sort (temp, temp + nblocks, cmp); // The system does not check whether the current scheme is duplicated with the previously generated scheme that fails to be spliced. This increases the search time. // However, if detected, a large number of solutions are generated, which requires a large amount of memory. // Reset the grid. Memset (cell, 0, sizeof (cell); // try to splice. Finished = false; fill (temp, 0, nblocks, false); if (finished) {smallest = nblocks; found = true ;}} else {// find the maximum edges that can be split. Int c, r, up, down, step; for (r = n-2; r> = 1; r --) if (area> = (r * r) break; c = r; step = (nblocks = 0 )? 1: (-1); r = (nblocks = 0 )? 1: r; for (; c> = 1; c --, r + = step) {// heuristic rules: the size of the first piece of paper is between n/2 + 1 and n-2. If (nblocks = 0 & r <(n/2 + 1) continue; // heuristic rule: the sum of the size of the second piece of paper and the size of the first one is n. If (nblocks = 1 & (r + blocks [0])! = N) continue; // heuristic rule: the size of the third piece of paper should be the same as that of the second one. If (nblocks = 2 & r! = Blocks [1]) continue; // heuristic rule: the sum of the sizes of the fourth and fifth pieces should be the size of the first piece of paper, // The number of pieces of paper on one side of the square produced by splicing cannot exceed 3. If (nblocks = 4 & (r + blocks [3])! = Blocks [0]) continue; // heuristic rule: no more than 4 pieces of paper of the same size. If (ncount [r] + 1)> 4) continue; ncount [r] ++; // records the current split. Blocks [nblocks] = r; // continue splitting. Cut_by_hard_work (area-(r * r), blocks, nblocks + 1); ncount [r] -- ;}} // use the generated minimum number of pieces of paper to obtain the splicing scheme. Void solve_it_by_trick () {// you can call this operation to find the resolution scheme of the corresponding prime number. Int blocks [NMAX]; int nblocks; for (int r = 0; r <NPRIME; r ++) if (trick [r] [0] = n) {// locate the data of the corresponding prime number, and set the total number of pieces of paper and the specific splitting scheme. Nblocks = trick [r] [1]; for (int c = 0; c <nblocks; c ++) blocks [c] = trick [r] [c + 2]; break;} // reset the end mark. Finished = false; // reset the grid array. Memset (cell, 0, sizeof (cell); // splice the square according to the best splitting scheme. Fill (blocks, 0, nblocks, true);} // use the number of pieces of paper in the minimum number of pieces of paper splitting scheme as the pruning threshold, and search for a feasible splicing scheme. Void solve_it_by_tip () {int blocks [NMAX]; finished = false; memset (ncache, 0, sizeof (ncache )); // if the number of paper required for a square with a splicing edge length of n provided by the network is used, the search time can be greatly reduced. Otherwise, the search time is long. Int goal = tip [n/2-1]; // use the Backtracking Method to split n * n into a number not greater than the sum of smallest shards. Cut_by_tip (n * n, blocks, 0, goal);} // obtain a better splicing pruning threshold by using the moving phase division of the maximum common number. Void gcd (int a, int B) {if (a <B) {int temp = a; a = B; B = temp;} smallest + = (a/B) * 2; if (a % B! = 0) gcd (a % B, B);} // a splicing scheme that generates the minimum number of pieces of paper completely based on real-time backtracking. Void solve_it_by_hard_work () {int current [NMAX]; memset (ncache, 0, sizeof (ncache )); // if the number of paper required for a square with a splicing edge length of n provided by the network is used, the search time can be greatly reduced. No // The search time is long. If this parameter is not used, you must dynamically adjust the value of smallest During calculation. When n increases gradually, You can // select a large piece of paper to fill in the value of the reduced pruning threshold. Smallest = 1 + n/2 + (n-2)/2 + 4; // when the n value is large, try to find a better pruning threshold. You can look for this: first put a piece of paper with a side length of s on the Left/side, and then put a piece of paper with a side length of (n-s) in the lower right corner, then fill in the remaining space with paper with a side length of (n-// s). Fill in the remaining space with a large square as much as possible, and fill in the remaining square paper with a side length of 1, in this way, // The obtained pruning threshold is better. In fact, we can use the division of the moving phase to obtain the maximum common divisor. Int threshold = smallest; for (int s = (n/2 + 1); s <(n-2); s ++) {smallest = 2; gcd (s, n-s); if (threshold> smallest) threshold = smallest;} smallest = threshold; // use backtracking to split n * n into the sum of the number of workers not greater than smallest. Cut_by_hard_work (n * n, current, 0); // output the best solution. Print (best, smallest);} // output a piece of paper with a size at the side of the coordinate (x, y. Void building (int x, int y, int size) {cout <x <"" <y <"" <size <endl ;} int main (int ac, char * av []) {# ifdef DEBUG_MODEclock_t start = clock (); # endifint cases; // Number of test data instances. Cin> cases; while (cases --) {cin> n; // if n is an even number, the splicing scheme is directly output. If (n % 2 = 0) {int size = n/2; cout <"4" <endl; building (1, 1, size); building (1, 1 + size, size); building (1 + size, 1, size); building (1 + size, 1 + size, size );} // if n is in the shape of 6 * m + 3, the splicing scheme is the same as that when n = 3, and the splicing scheme is directly output. Else if (n % 6 = 3) {int size = n/3; cout <"6" <endl; building (1, 1, size * 2 ); building (1 + size * 2, 1, size); building (1 + size * 2, 1 + size, size); building (1 + size * 2, 1 + size * 2, size); building (1, 1 + size * 2, size); building (1 + size, 1 + size * 2, size );} // For m and n, m is the prime number and is the smallest prime number that can be divisible by n, g (m) = g (n) is available, and // The splicing scheme is similar. If n is an odd number and 5 is the minimum prime number that can divide n, g (5) = g (n), // includes 5 and 25. Else if (n % 5 = 0) {int size = n/5; cout <"8" <endl; building (1, 1, size * 3 ); building (1 + size * 3, 1, size * 2); building (1 + size * 3, 1 + size * 2, size * 2); building (1, 1 + size * 3, size * 2); building (1 + size * 2, 1 + size * 3, size); building (1 + size * 2, 1 + size * 4, size); building (1 + size * 3, 1 + size * 4, size); building (1 + size * 4, 1 + size * 4, size);} // if n is an odd number, and 7 is the minimum quality that can divide n Number, then g (7) = g (n), including 7 and 49. Else if (n % 7 = 0) {int size = n/7; cout <"9" <endl; building (1, 1, size * 4 ); building (1 + size * 4, 1, size * 3); building (1, 1 + size * 4, size * 3); building (1 + size * 3, 1 + size * 5, size * 2); building (1 + size * 5, 1 + size * 5, size * 2); building (1 + size * 5, 1 + size * 3, size * 2); building (1 + size * 4, 1 + size * 3, size); building (1 + size * 4, 1 + size * 4, size); building (1 + size * 3, 1 + size * 4, size);} // in other cases, find a solution that satisfies the question. Else {// use the generated splitting scheme to try stitching. Using this method, the RT is 0.032 s. Solve_it_by_trick (); // use the minimum number of pieces of paper directly as the pruning threshold and use the backtracking method to obtain the splitting scheme, use this // method to obtain that the running time of all prime numbers in the range of 10-50 is 27 s. // Solve_it_by_tip (); // obtain the splitting scheme based on real-time backtracking, and then try to splice the scheme. The pruning threshold value uses the number of unoptimal schemes. This method is used in my notebook (Intel Core2 T5200 1.60 GHz, // 2.0GiB memory) to run for more than half an hour to get a 10-50 quality stitching solution. // Solve_it_by_hard_work () ;}# ifdef DEBUG_MODEcout <"time elapsed:" <(clock ()-start)/CLOCKS_PER_SEC <"s. "<endl; # endifreturn 0 ;}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.