Start with the zero-based backtracking algorithm

Source: Internet
Author: User

This article in the writing process reference a lot of information, can not be enumerated, but also forgive me.
The definition of backtracking algorithm: The backtracking algorithm is also called Heuristic method, which is a method to search the solution of the problem systematically. The basic idea of backtracking algorithm is: Go forward from a road, can enter into, can not enter the back, change a road and try again.
The general steps to solve the problem are:
1. Define a solution space, which contains the solution of the problem;
2. Use the appropriate search method to organize the solution space;
3. Search for solution space using depth-first method;
4. Use the gauge function to avoid moving to a subspace that cannot produce a solution.
The solution space of the problem is usually generated dynamically in the process of searching the solution of the problem, which is an important feature of backtracking algorithm.
Without saying much, let's look at a few concrete examples to understand it slowly:
1. Eight Queen's question
The problem is the international chess player Max Bessel in 1848: Put eight queens on the 8x8 chess, so that they can not attack each other, that is, any two queens can not be in the same row, the same column or the same slash, ask how many kinds of pendulum. The following solution refers to the "Algorithmic competition Primer". If we place the Queen row by line, there will be no two queens on the same line, just a column and a diagonal. Use a two-dimensional array vis[3][], where Vis[0][i] represents a column, Vis[1][i], and vis[2][i] represents a diagonal line. Because the Y-x value (x, y) identifies the main diagonal, the X+y value identifies the secondary diagonal. Because y-x may be negative, add N to the access.


 #include  <cstring> #include <iostream>using namespace std;  int Vis[3][15],tot;      void search (int cur) {int i,j;    if (cur==8) tot++; else {for (i=0;i<8;i++) {if (!vis[0][i]&&!vis[1][cur-i+8]&&!vis[2][cur+                  I]) {vis[0][i]=1;                  Vis[1][cur-i+8]=1;                    Vis[2][cur+i]=1;                  Search (cur+1);                       Change back to the auxiliary global variable vis[0][i]=0;                  vis[1][cur-i+8]=0;              vis[2][cur+i]=0;       }}}} int main () {search (0); Cout<<tot<<endl;} 

2. Coloring Problems of graphs
Given the undirected connected graph g= (v,e) and M different colors, these colors are used to color each vertex of figure g, each vertex with a color. If a graph requires a minimum of M colors to make the 2 vertices connected by each edge of the graph different colors, then M is the number of colors for the graph. Map coloring problem can be converted to the coloring problem of graphs: the area in the map as the vertex, 2 regions if the adjacency, then the 2 regions corresponding to the vertex has an edge, that is, the edge represents the adjacency relationship between the regions. The famous four-color theorem means that each plane map can be dyed with only four colors, and no two contiguous areas have the same color.

Given the number of graphs and colors to find out the number of shading methods, you can use the backtracking method.
#define N 100#include<iostream>using namespace Std;int v,e,c,graph[n][n],color[n];//vertices, number of sides, number of colors int Sum;bool OK ( int k) {for (int j=1;j<=v;j++) {if (graph[k][j]&& (Color[j]==color[k])) return false;} return true;} void backtrack (int t) {if (t>v) sum++; else {for    (int i=1;i<=c;i++) {color[t]=i;   if (OK (t)) backtrack (t+1);   Change back to the auxiliary global variable Color[t]=0;}}}    int main () {    int i,j;    cin>>v>>e>>c;                for (i=1;i<=v;i++) {for (j=1;j<=v;j++) {graph[i][j]=0;}}           for (int k=1;k<=e;k++)      {cin>>i>>j;graph[i][j]=1;graph[j][i]=1;} for (i=0;i<=v;i++) color[i]=0; Backtrack (1);  Cout<<sum<<endl;}

3. Loading issues

There are a batch of n containers to be loaded with 2 load capacity of C1 and C2, of which the weight of container I is WI, and. The loading problem requires determining if there is a reasonable loading plan to load the containers onto these 2 vessels. If so, find a loading scheme. For example, when N=3,c1=c2=50 and w=[10,40,40], containers 1 and 2 can be installed on the first ship, and the container 3 on the second ship, if W=[20,40,40], the 3 containers will not be installed on the ship. It is easy to prove that if a given loading problem has a solution, the first ship will be filled as far as possible and the remaining containers will be loaded with the second vessel for the optimal loading scheme. Fill the first ship as much as possible equivalent to selecting a subset of the entire container, so that the sub-centralized container weight of the nearest c1. Using backtracking method to solve loading problem,   time complexity O (2^n), in some cases, better than dynamic programming algorithm. The pruning scheme is to delete the branch if the weight of the remaining container is cw+ r<= the current known optimal load weight BESTW If all items currently selected are loaded.

#include <iostream>using namespace std; int n;//container number int w[40];//container weight int c1,c2;//Two ships load capacity int ans;//current load weight int bestans;//current optimal load int r;//remaining container weight void backtr  ACK (int i) {if (i>n) {if (Ans>bestans) Bestans=ans;      Return      } R-=w[i];        if (ANS+W[I]&LT;=C1) {ans+=w[i];        Backtrack (i+1);      Change back to the auxiliary global variable ans-=w[i];        } if (Ans+r>bestans) backtrack (i+1);  Change back to the auxiliary global variable r+=w[i];  } int maxloading () {ans=0;      bestans=0;       Backtrack (1);  return Bestans;   }int Main () {cin>>n>>c1>>c2;   int i=1;   int sum=0;  Total container weight while (i<=n) {cin>>w[i];  R+=w[i];   Sum+=w[i];   i++;  } maxloading ();   if (bestans>0&& (Sum-bestans) <=c2) cout<<bestans<<endl;    else if (SUM&LT;=C2) cout<<bestans<<endl;  else cout<< "No" <<endl; }

4. Travel Business Issues
The traveling salesman problem is the TSP problem (traveling salesman problem). Suppose there is a travel merchant to visit N cities, he must choose the path to go, the limit of the path is that each city can only visit once, and finally return to the original city of departure. The path selection target is the minimum required path distance for all paths. The TSP problem is an NPC problem. W (VI,VJ) represents the direct distance between city I and J, and W (VI,VJ) =∞ indicates that there is no direct path between City I and J. The n vertices in the figure are numbered,..., N, starting with vertex 1, the travel loop is described as 1,x1,x2, xn,1, where x1,x2, ..., xn is a vertex 2,3,4,..., N of 1 permutations. So the solution space size is (n-1)!.
There are two pruning constraints:
1. If the vertex J currently being considered is not connected to the end node I in the current path, i.e. W[i, j]=∞, you do not have to search for the branch where J is located.


For example, the current part of the path is <1,2,?,?, the end of the path node is 2, according to the path composition rules, the next step is to consider adding vertices 3, 4 to the partial path. However, Vertex 2 and 4 are boundless, W (2,4) =∞, so it is not necessary to consider the branch where Vertex 4 is located.
2. To the level I node, the structure of the partial solution path is <1,x[2],x[3],..., x[i-1], X[i],?,?,?, the sum of the weights of the path is

Assuming that it is known until part of the I-1 layer is <1, x[2],x[3],..., x[i-1],?,? , i-1, select Vertex x[i] from the first layer node, and search the branch down to the boundary function B (i) =CW (i-1) +w (X[i-1],x[i]), if B (i) ≥BESTW stop searching x[i] branch and its lower layer, Where BESTW represents the total length of the best complete loop found so far in the previous search, from other already searched paths.


The optimal solution for this problem is <1,3,2,4,1> and <1,4,2,3,1>, and the corresponding bestw=25. Suppose the search for another branch <1,3,4,?>, the current path corresponding to the node is I, the length of =6+20=26>bestw=25, then the path below node I is discarded.

#include <cstring> #include <iostream> #define INF 10000using namespace Std;int n,m;//n dot m edge int bestans=inf, ans=0;//Optimal and current solution int bestroad[100],road[100];//best path and current path int graph[100][100];//graph of matrix bool vis[100];//access mark void backtrack (int i) {if (i>n) {if (graph[road[n]][1]!=inf&& (ans+graph[road[n]][1]) <bestans) {Bestans=ans+graph[road[n]] [1];for (int j=1;j<=n;j++) bestroad[j]=road[j];}} else {for (int j=1;j<=n;j++) {if (graph[road[i-1]][j]!=inf&&ans+graph[road[i-1]][j]<bestans&&        !vis[j]) {road[i]=j;      Ans+=graph[road[i-1]][j];vis[j]=1;backtrack (i+1);//change back to the auxiliary global variable ans-=graph[road[i-1]][j];vis[j]=0; }}}}int Main () {memset (graph,inf,sizeof); cin>>n>>m;for (int i=1;i<=m;i++) {int a,b;cin>> A&GT;&GT;B;CIN&GT;&GT;GRAPH[A][B];GRAPH[B][A]=GRAPH[A][B];} vis[1]=1;road[1]=1;//hypothesis is starting from 1 backtrack (2); cout<<bestans<<endl;for (int i=1;i<=n;i++) cout<<   bestroad[i]<< ""; Cout<<1<<endl;}                   

5. batch job scheduling issues
A collection of n jobs given {j1,j2,..., Jn}. Each job must first be processed by machine 1 and then handled by Machine 2. Operation Ji Need (1≤i≤n) to Machine J (1≤j≤2) processing time is Tji. For a definite job schedule, set Fji is the time that job I finishes processing on machine J. The time that all jobs finish processing on machine 2 and the completion time called the job schedule and:. The optimal job scheduling scheme is required for a given n jobs, and the completion time and minimum are achieved.

Tji Machine 1 Machine 2
Job 1 2 1
Job 2 3 1
Job 3 2 3

For example, for the situation shown in this table, there are 3!=6 possible scheduling scenarios for 3 jobs, and it is clear that the worst-case complexity is O (n!). If you follow the order of 2,3,1, the completion time for Job 2 is 4, job 3 finishes at 8, and job 1 finishes at 9, completion time, and 21. The optimal scheduling scheme for the job scheduling is 1,3,2, and its completion time is 18.

#define MAX 200#include<iostream>using namespace std;int* x1;//job Ji working time on machine 1 int* x2;//job Ji on machine 2 working time int number Number of =0;//jobs int* xorder;//Job order int* bestorder;//Optimal Job order int bestvalue=max;//optimal time int xvalue=0;//current completion time int f1=0;// Machine 1 completed time int* f2;//Machine 2 completed time void backtrack (int k) {if (K>number) {for (int i=1;i<=number;i++) bestorder[i]=xorder[i  ]; Bestvalue=xvalue;}           else{for (int i=k;i<=number;i++) {f1+=x1[xorder[i]];           f2[k]= (F2[K-1]&GT;F1?F2[K-1]:F1) +x2[xorder[i];           XVALUE+=F2[K];           Swap (xorder[i],xorder[k]);           if (xvalue<bestvalue) backtrack (k+1);           Swap (xorder[i],xorder[k]);           XVALUE-=F2[K]; F1-=x1[xorder[i]];}}  int main () {cout<< "Please enter the number of jobs:"; cin>>number;x1=new int[number+1]; x2=new int[number+1];   Xorder=new int[number+1];   Bestorder=new int[number+1];   F2=new int[number+1];   x1[0]=0;   x2[0]=0;   xorder[0]=0;    bestorder[0]=0;    f2[0]=0;    cout<< "Please enter the time spent on machine 1 per job:" <<endl; int i;   for (i=1;i<=number;i++) {cout<< "first" <<i<< "job =";cin>>x1[i]; }cout<< "Please enter the time spent on machine 2 per job:" <<endl;     for (i=1;i<=number;i++) {cout<< "<<i<<" jobs = ";  cin>>x2[i];    } for (i=1;i<=number;i++) xorder[i]=i;    Backtrack (1);    cout<< "The most time to save:" <<bestvalue<<endl;    cout<< "The corresponding scheme is:";    for (i=1;i<=number;i++) cout<<bestorder[i]<< ""; Cout<<endl;}
6. Further discussion on knapsack problem
We have discussed the knapsack problem in the zero-based dynamic programming and the zero-based greedy algorithm, where we once again use backtracking to solve the classic 01 knapsack problem.
 #include <iostream>using namespace Std;int n,c,bestp;//number of items, backpack capacity, maximum value int p[10000],w[10000],x[10000],bestx[10000];// The value of the item, the weight of the item, the selected condition of the item void backtrack (int i,int cp,int CW) {if (i>n) {if (CP>BESTP) {Best            P=CP;        for (i=1;i<=n;i++) bestx[i]=x[i];            }} else{for (int j=0;j<=1;j++) {x[i]=j;                if (cw+x[i]*w[i]<=c) {cw+=w[i]*x[i];                Cp+=p[i]*x[i];                Backtrack (I+1,CP,CW);                Cw-=w[i]*x[i];            Cp-=p[i]*x[i];     }}}}int Main () {bestp=0;    cin>>c>>n;    for (int i=1;i<=n;i++) cin>>w[i];    for (int i=1;i<=n;i++) cin>>p[i];    Backtrack (1,0,0); Cout<<bestp<<endl;} 

7. Maximum Regiment problem
Given the g= graph (V, E), U is a subset of V. If to any u,v belongs to U has (u,v) belongs to E, then the U is called a complete sub-graph of G. The complete sub-figure U of G is the Regiment of G when and only if u is not contained in a larger complete sub-diagram of G. The largest group of G is the group with the highest number of vertices in G. If to any u,v belongs to u having (U, v) does not belong to E, then it is called U is the empty view of G. The empty picture of G is the independent set of G when and only if u is not contained in a larger empty view of G. The largest independent set of G is the independent set with the highest number of vertices in G. G's complement graph g ' = (v ', E ') is defined as V ' =v and (U, v) belongs to E ' when and only if (U, v) does not belong to E.
, given the graph g={v, E}, where v={1,2,3,4,5},e={, (1,4), (1,5), (2,3), (2,5), (3,5), (4,5)}. According to the maximum group definition, the subset {"A" is a full sub-figure with a size of 2 in Figure G, but not a regiment because it is contained in the larger complete sub-graph {1,2,5} of G. {1,2,5} is one of the largest groups of G. {1,4,5} and {2,3,5} are also the largest groups of G. The graph on the right is the G ' complement to the graph G. According to the maximum independent set definition, {2,4} is an empty view of G and a maximum independent set of G. Although {The} is also an empty map of G ', it is not a separate set of G ' because it is contained in the empty diagram {1,2,5} of G '. {1,2,5} is the largest independent set of G '. {1,4,5} and {2,3,5} are also the largest independent sets of G '.


The maximum regiment problem can be solved by backtracking in O (n2^n) time. First, set the largest regiment as an empty regiment, add a vertex to it, and then consider each vertex in turn, to see if the vertex joins the regiment and still form a regiment. The program uses a simple pruning strategy, that is, if the remaining number of outstanding vertices plus the number of vertices in the regiment is not greater than the number of vertices of the current solution, you can stop backtracking. The adjacency matrix is used to represent the number of vertices of the graph g,n to G, CN stores the vertices of the current regiment, and BESTN stores the maximum number of vertices of the regiment. When Cn+n-i<bestn, the larger regiment cannot be found, and the pruning function is used to cut it.

#include <iostream>using namespace Std;const int Maxnum=101;bool Graph[maxnum][maxnum];bool use[maxnum],bestuse [Maxnum];        int cn,bestn,v,e;void backtrack (int i) {if (i>v) {if (CN&GT;BESTN) {BESTN=CN;        for (int j=1;j<=v;j++) BESTUSE[J]=USE[J];    Return    }} bool Flag=true;            for (int j=1;j<i;j++) {if (Use[j]&&!graph[j][i]) {flag=false;        Break        }} if (flag) {cn++;        Use[i]=true;        Backtrack (i+1);        Use[i]=false;    cn--;        } if (CN+V-I&GT;BESTN) {use[i]=false;    Backtrack (i+1);    }}int Main () {cin>>v>>e;    for (int i=1;i<=e;i++) {int p1,p2;  cin>>p1>>p2;  Graph[p1][p2]=true;    Graph[p2][p1]=true;    } backtrack (1);    cout<<bestn<<endl;    for (int i=1;i<=v;i++) {if (Bestuse[i]) cout<<i<< "";}  cout<<endl; }
8. Circular arrangement Problems

Given n sizes of round C1,C2,..., cn, the N circles are now queued in a rectangular box, and each circle is required to be tangent to the bottom edge of the rectangle box. The circular arrangement problem requires that a circular arrangement with a minimum length be found in all permutations of n circles. For example, when n=3, and the radius of the given 3 circles is 1,1,2, the minimum-length circle of the 3 circles is arranged. Its minimum length is.



Notice that the center axis of the circle in the following code is the origin of the center point of the first circle. Therefore, the total length is the radius of the first circle + the radius of the last circle + the horizontal axis of the last circle.

#include <cmath> #include <iostream> #include <algorithm>using namespace Std;float minlen=10000,x[4] , r[4];//current optimal value, the current circle is arranged at the center of the horizontal axis, the current circle arranges int n;//The number of circles in the circle//calculates the center axis of the currently selected circle, a float center (int t) {float temp=0;for (int j=1;j<t;j    + +) {//by X^2=SQRT ((R1+R2) ^2-(R1-R2) ^2) derived from float valuex=x[j]+2.0*sqrt (r[t]*r[j]), if (valuex>temp) Temp=valuex; } return temp;}        Calculates the length of the current circle arrangement void compute () {float low=0,high=0;for (int i=1;i<=n;i++) {if (x[i]-r[i]<low) low=x[i]-r[i];    if (X[i]+r[i]>high) high=x[i]+r[i]; } if (High-low<minlen) Minlen=high-low;}    void backtrack (int t) {if (t>n) compute (); else{for (int j=t;j<=n;j++) {swap (r[t],r[j]), float centerx=center (t), if (Centerx+r[t]+r[1]<minlen) {x[t]= Centerx;backtrack (t+1);} Swap (R[t],r[j]);}} int main () {n=3; r[1]=1,r[2]=1,r[3]=2;cout<< "radius of each circle is:" <<endl;for (int i=1;i<=3;i++) Cout<<r[i] << ";cout<<endl;cout<<" The minimum Circle arrangement length is: "; backtrack (1); Cout<<minlen<<endl;}

There is still much room for improvement in the algorithms described above. For example, like,..., n-1,n and n,n-1, ..., 2,1 this kind of mutual mirror arrangement has the same circular arrangement length, only one is sufficient. Also, if there are k circles in the given n circle with the same radius, then this K-Circle produces a k! of exactly the same circle, and only needs to calculate one.  
9. Continuous postage issues
assume that the state has issued stamps of different denominations of K, and that only H stamps are allowed on each envelope. The question of continuous postage requires the best design for a given value of K and H, with a maximum continuous postage range of 1 envelopes, starting from postage 1 and increments of 1. For example, when K=5 and h=4, 5 stamps with a face value of (1,3,11,15,32) can be posted with a maximum continuous postage range of 1 to 70. UVA165 is such a typical example. Use Stampval to save each face value and use Maxval to save the maximum contiguous face value of all current denominations. So, stampval[0] must be equal to 1, because 1 is the smallest positive integer. Accordingly, the maxval[0]=1*h. The next step is to make sure the second one, the third one ... The face value of the K stamps. For stampval[i+1], its value range is stampval[i]+1~maxval[i]+1.  stampval[i]+1 is because this time the face value is certainly higher than the last face value, and this time the upper limit of the face value of the last can reach the largest consecutive face value of +1, is because if larger than this, then there will be a fault, that is, unable to form the last maximum value of +1 this number. For example, assuming that 3 stamps can be affixed, there are 3 denominations, the front 2 denominations have been identified as 1, 2, can reach the maximum continuous face value of 6, then the next 3rd denomination values range of 3~7. What if it gets bigger than 7? Hands down to know, assuming 8, then the face value of 1,2,8, will not be able to combine 7. The maximum number of consecutive values can be known by direct recursive backtracking in all cases.

#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #define MAXN usi  NG namespace Std;  int h,k,ans[maxn],stampval[maxn],maxval[maxn],maxstampval;  BOOL VIS[MAXN];  Mark each fetch of void mark (int n,int m,int sum) {if (m>h) return;    Vis[sum]=true;    for (int i=1;i<=n;++i) mark (N,m+1,sum+stampval[i]); } void Backtrack (int cur) {if (cur>k) {if (maxval[cur-1]>maxstampval) {MAXSTAMPVAL=MAXVA              L[CUR-1];          memcpy (ans,stampval,sizeof (stampval));      } return;          } for (int i=stampval[cur-1]+1;i<=maxval[cur-1]+1;++i) {memset (vis,0,sizeof (VIS));          Stampval[cur]=i;          Mark (cur,0,0);          int num=0,j=1;          while (vis[j++]) ++num;          Maxval[cur]=num;      Backtrack (cur+1);          }} int main () {while (scanf ("%d%d", &h,&k), h+k) {maxval[1]=h;          Stampval[1]=1;          Maxstampval=-1;          Backtrack (2);for (int i=1;i<=k;++i) printf ("%3d", Ans[i]);      printf ("->%3d\n", maxstampval);  }    }

The solution complexity of direct recursion is too high, try to calculate the minimum number of stamps required to post postage K for a stamp with no more than M-x[1:i] y[k]. The value of R can be introduced very quickly via Y[k]. In fact, Y[k] can be resolved by recursion within O (n) time. This is no longer explained here.
10. Symbolic triangle problem
is a symbolic triangle consisting of 14 "+" and 14 "-", with n symbols in the first row. 2 of the same number below are "+", 2 different numbers below are "-". The

Symbol triangle problem requires that for a given n, the number of different symbolic triangles is calculated so that they contain the same numbers of "+" and "-". After the 1th line of the first I symbol X[1:I] is determined, the 1 triangles consisting of I (i+1)/2 symbols are determined. After you determine the first i+1 symbol, add 1 edges to the right, and you can expand to the new triangle corresponding to the previous i+1 symbol x[1:i+1]. This expands in turn until X[1:n]. The symbolic triangle determined by x[1:n] has the number of "+" and "-" as N (n+1)/4. Therefore, the current symbol triangle contains the number of "+" and "-" no more than n (n+1)/4, you can use this condition to cut the branch. For a given n, when n (n+1)/2 is odd, there is obviously no sign triangle with the same number of "+" numbers as the number of "-" numbers. A simple judgment is needed before backtracking.

#include <iostream> using namespace std;       int n,half,counts,p[100][100],sum;//The number of symbols for the first line, N (n+1)/4, the number of the current "+" number, the symbol triangle matrix, the number of symbol triangles found, void backtrack (int t) { if ((counts>half) | | | (t* (t-1)/2-counts>half))      Return        if (t>n) sum++;              else {for (int i=0;i<2;i++) {p[1][t]=i;//first line symbol counts+=i;//current ' + ' number                  for (int j=2;j<=t;j++) {p[j][t-j+1]=p[j-1][t-j+1]^p[j-1][t-j+2];              COUNTS+=P[J][T-J+1];              } backtrack (t+1);              for (int j=2;j<=t;j++) {counts-=p[j][t-j+1];          } counts-=i;  }}} int main () {cin>>n;      half=n* (n+1)/2; if (half%2==1) {cout<< "Total" <<sum<< "a different symbol triangle."    "<<endl;return 0;       } HALF=HALF/2;      Backtrack (1); cout<< "Total" <<sum<< "a different symbol triangle."  "<<endl;}
The basics of backtracking algorithms are briefly introduced here, and we hope to be the basis for further study.


Start with the zero-based backtracking algorithm

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.