// Playing with wheels (playing with wheels) // PC/Ultraviolet IDs: 110902/10067, popularity: C, success rate: average level: 2 // verdict: accepted // submission date: 2011-09-26 // UV Run Time: 0.380 S // copyright (c) 2011, Qiu. Metaphysis # Yeah dot net // [Problem description] // It is a mathematical instrument with continuous numbers 0 ~ 9 is printed clockwise on the periphery of each gear. The highest number of each gear is a four-digit number. For example, the following gears constitute an integer of 8056. Each gear has two buttons. When you press the left arrow, the gear moves a letter clockwise. When you press the right arrow, the gear moves in the opposite direction. /// 8 0 5 6 // 7 9 9 1 4 6 5 7 // 6 0 8 2 3 7 4 8 // 5 1 7 3 2 8 3 9 // 4 2 6 4 1 9 2 0/3 5 0 1 ////<=>><=>><=><=>><== >>//// start, the top number of the gear is s1s2s3s4, giving you n prohibited numbers fi1fi2fi3fi4 (1 <= I <= N) and // one target number t1t2t3t4, if your task cannot be counted in the middle, press the button as few as possible to get the target number. //// [Input] // the first line of the input contains an integer N, representing the number of test data. Next there is a blank line. // The first line of each set of data describes the initial state of these gears, represented by four numbers, each of which is separated by a space. The following // row is the number of targets. The third row has an integer N, indicating the number of disallowed numbers. The next n rows have a number of prohibitions in each line. There is an empty row between two adjacent groups of input/output data. //// [Output] // for each set of input data, the first line is output, indicating the minimum number of times you need to press the button. If the task cannot be completed, output "-1 ". //// [Sample input] // 2 /// 8 0 5 6 // 6 5 0 8 // 5 // 8 0 5 5 7 // 8 0 4 7 // 5 5 0 8 // 7 5 0 8 // 6 4 0 8 // 0 0 0 0 // 5 3 1 7 // 8 // 0 0 0 1 // 0 0 0 9 // 0 0 1 0 // 0 0 9 0 // 0 1 0 0 // 0 9 0 0 // 1 0 0 0 0/9 0 0 0 //// [sample output] // 14 //-1 /// [solution] // The question is displayed, each four-digit can be changed to the other eight numbers by pressing the left and right arrows. In fact, these numbers constitute a undirected/connected graph without a self-ring, starting from the given number, finding the target number is equivalent to finding the shortest path between given vertices. Because the number of disallowed values can be obtained in the middle, you can remove the vertex represented by the number of disallowed numbers and then find the shortest path. //// Note: the data format on the ultraviolet A is not as strict as the description of the topic. Therefore, when reading data, pay attention to the fact that the algorithm is correct and the submitted program is always wa, you can try the following test data (note that there is no blank row after the first row of the test data, but there is a blank row in the middle, which is often the case on the data on the Apsara stack management framework ): // 2 // 1 7 4 0 // 9 4 8 8 // 2 // 4 5 5 1 // 7 1 5 // 3 4 8 4 // 9 9 2 5 // 5 // 3 3 3 7 // 4 3 8 0 // 8 8 8 0 6 // 8 1 9 8 // 9 7 2 2 # include <iostream> # include <algorithm> # include <cstring> # include <queue> using namespace STD; # define maxv 10000 # define maxdegree 8 # define nbase 10 # Defin E ndigits 4 // graph structure. Struct graph {int edges [maxv] [maxdegree]; // use an adjacent table to represent an edge. Int degree [maxv]; // Number of edges connected to the vertex .}; Bool processed [maxv]; bool discovered [maxv]; int parent [maxv]; // The length of the output shortest path. Int find_path (INT start, int target) {int steps = 1; while (parent [target]! = Start) {steps ++; target = parent [target];} return steps;} // use width for priority search. Int breadth_first_search (graph * g, int start, int target) {queue <int> q; q. Push (start); discovered [start] = true; while (! Q. Empty () {int v = Q. Front (); q. Pop (); // traverse the number adjacent to the number v. Processed [v] = true; For (INT I = 0; I <G-> degree [v]; I ++) {If (discovered [G-> edges [v] [I] = false) {q. push (G-> edges [v] [I]); discovered [G-> edges [v] [I] = true; parent [G-> edges [v] [I] = V ;}// if not processed, check whether it is the target number. If (processed [G-> edges [v] [I] = false) if (G-> edges [v] [I] = target) return find_path (start, target) ;}} return-1 ;}// generate eight numbers connected to the current number. Void generate_neighbor (INT current, int neighbor []) {int digits [ndigits], temp [ndigits], Count = 0; // split the number current into numbers. Memset (digits, 0, sizeof (digits); While (current) {digits [count ++] = Current % nbase; current/= nbase;} // generate adjacent numbers. Count = 0; For (INT I = 0; I <maxdegree; I ++) {memcpy (temp, digits, sizeof (digits )); temp [I/2] + = (I % 2 )? -1: 1); If (temp [I/2]> = 0) temp [I/2] % = nbase; elsetemp [I/2] + = nbase; int number = 0; For (Int J = ndigits-1; j> = 0; j --) number = Number * nbase + temp [J]; neighbor [count ++] = Number ;}// initialization diagram. Void initialize_graph (graph * g) {// The flag used to search for initialization width first. Memset (processed, false, sizeof (processed); memset (discovered, false, sizeof (discovered); memset (parent,-1, sizeof (parent )); memset (G-> degree, 0, sizeof (G-> degree); For (INT I = 0; I <maxv; I ++) {int neighbor [maxdegree]; generate_neighbor (I, neighbor); memcpy (G-> edges [I], neighbor, sizeof (neighbor); G-> degree [I] = maxdegree ;}} bool CMP (int x, int y) {return x> Y;} // remove the edge connected to forbidden. Void remove_edge (graph * g, int forbidden) {for (INT I = 0; I <G-> degree [forbidden]; I ++) {int v = G-> edges [forbidden] [I]; for (Int J = 0; j <G-> degree [v]; j ++) if (G-> edges [v] [J] = forbidden) {G-> edges [v] [J] = 0; sort (G-> edges [v], g-> edges [v] + maxdegree, CMP); G-> degree [v] --; break ;}} G-> degree [forbidden] = 0; memset (G-> edges [forbidden], 0, maxdegree * sizeof (INT);} // converts a string to an integer. Int read (void) {int digit, number = 0; For (INT I = 0; I <ndigits; I ++) {CIN> digit; number = Number * nbase + digit;} return number;} int main (int ac, char * AV []) {INT cases, start, target, forbidden, nforbidden; graph G; cin> cases; while (cases --) {// build a graph. Initialize_graph (& G); Start = read (); target = read (); CIN> nforbidden; For (INT I = 0; I <nforbidden; I ++) {forbidden = read (); remove_edge (& G, forbidden);} // if the initial state is the same as the target State, no need to press the button. If (START = target) {cout <"0" <Endl; continue;} // if the specified number of initial states or number of target States is 0, this is not possible. If (G. degree [start] = 0 | G. degree [target] = 0) {cout <"-1" <Endl; continue;} // use the width to search for the shortest path length first. Cout <breadth_first_search (& G, start, target) <Endl;} return 0 ;}