码迷,mamicode.com
首页 > 其他好文 > 详细

回溯法小实例

时间:2014-06-14 20:30:24      阅读:328      评论:0      收藏:0      [点我收藏+]

标签:style   class   blog   code   http   tar   

1、图的m着色问题:

bubuko.com,布布扣
 1 /*
 2 *问题描述:给定无向连通图G和m种不同的颜色。用这些颜色为图G的各个顶点着色,每个顶点着一种颜色。是否有一种着色法使G中每条边的两个顶点着不同的颜色。
 3 *           这个问题是图的m可着色判定问题。若一个图最少需要m中颜色才能使图中每条边连接的2个顶点着不同的颜色,则称这个数m为该图的色数。
 4 *算法分析:给定图G=(V,E)和m中颜色,如果这个图不是m可着色,给出否定回答;如果这个图是m可着色的,找出所有不同的着色法。
 5 *           回溯法+子集树
 6 *           问题的解空间可表示为一棵高度为n+1的完全m叉树,解空间树的第i层中每一个结点都有m个儿子,每个儿子相应于x[i]的m个可能的着色之一,第n+1层结点均为叶结点。        
 7 *算法效率:图m可着色问题的解空间树中的内结点个数是m^i之和(i从0到n-1),在最坏的情况下,用ok检查当前扩展结点的每一个儿子所相应的颜色的可用性需耗时O(mn)。
 8            因此回溯总的耗时为mn(m^n-1)/(m-1)=O(nm^n)
 9 *附    注:初始化无向图矩阵的时候对角线赋值为0!!! 
10 *Author:xymaqingxiang
11 *Time:2014--5-22
12 */
13 
14 #include <fstream>
15 #include <iostream>
16 #include <stdlib.h>
17 #include <conio.h>
18 using namespace std;
19 
20 #define MAX_v 50 //定义一个最大顶点个数
21 typedef struct{
22     int a[MAX_v][MAX_v]; //无向图G的邻接矩阵
23     int n; //无向图G的顶点数
24     int m; //无向图G的颜色数
25     int x[50]; //当前解
26     long sum;//当前已找到的可m着色的方案数
27 }MC;
28 
29 void Creat(MC &G);
30 void Backtrack(MC &G,int t);
31 
32 void Creat(MC &G){
33     int i,j;
34     ifstream fin("data.txt");
35     if (!fin)
36     {
37         cout<<"不能打开文件:"<<"data.txt"<<endl;
38         exit(1);
39     }
40     fin>>G.n;
41     fin>>G.m;
42     for (int i=1;i<=G.n;i++)
43         for (int j=1;j<=G.n;j++)
44             fin>>G.a[i][j];
45     for(i=1;i<=G.n;i++) //初始化
46     {
47         G.x[i]=0;
48         G.sum=0;
49     }
50     cout<<"———回溯法求解图的m着色问题———"<<endl;
51     cout<<"输入初始化无向图矩阵为:"<<endl; //初始化
52     for(i=1;i<=G.n;i++)
53     {
54         for(j=1;j<=G.n;j++)
55             cout<<G.a[i][j]<<" ";
56         cout<<endl;
57     }
58     cout<<"输入初始化无向图顶点数为:"<<" "; //初始化
59     cout<<G.n<<endl;
60     cout<<"输入初始化无向图着色数为:"<<" "; //初始化
61     cout<<G.m<<endl;
62 }
63 
64 bool ok(MC &G,int k)
65 {
66     for(int j=1;j<=G.n;j++)
67         if(G.a[k][j]==1&&G.x[j]==G.x[k])    //先后顺序——先判断是否相邻,然后判断颜色是否相同
68             return false;
69     return true;
70 }
71 
72 void Backtrack(MC &G,int t){
73     if (t>G.n){        //output()阶段
74         G.sum++;
75         for (int j=1; j<=G.n; j++)
76             cout<<G.x[j]<< ;
77         cout<<endl;
78     }
79     else
80     {
81         for(int i=1;i<=G.m;i++)
82         {
83             G.x[t]=i;
84             if(ok(G,t))
85                 Backtrack(G,t+1);
86             G.x[t]=0;    //递归回退时返回上一层,着色赋初值0
87         }
88     }
89 }
90 
91 int main(){
92     MC G;
93     Creat(G);
94     Backtrack(G,1);
95     getch();
96 }
图的m着色问题

 

2、电路板排列问题:

bubuko.com,布布扣
  1 /*
  2 问题描述:将n块电路板以最佳排列方式插入带有n个插槽的机箱中。n块电路板的不同排列方式对应于不同的电路板插入方案。
  3           设B={1, 2, …, n}是n块电路板的集合,L={N1, N2, …, Nm}是连接这n块电路板中若干电路板的m个连接块。Ni是B的一个子集,且Ni中的电路板用同一条导线连接在一起。
  4           设x表示n块电路板的一个排列,即在机箱的第i个插槽中插入的电路板编号是x[i]。x所确定的电路板排列Density (x)密度定义为跨越相邻电路板插槽的最大连线数。
  5           在设计机箱时,插槽一侧的布线间隙由电路板的排列的密度确定。因此,电路板排列问题要求对于给定的电路板连接条件(连接块),确定电路板的最佳排列,使其具有最小密度。
  6 
  7 算法设计:电路板排列问题是NP难问题,因此不大可能找到解此问题的多项式时间算法。考虑采用回溯法系统的搜索问题解空间的排列树,找出电路板的最佳排列。设用数组B表示输入。
  8           B[i][j]的值为1当且仅当电路板i在连接块Nj中。设total[j]是连接块Nj中的电路板数。对于电路板的部分排列x[1:i],设now[j]是x[1:i]中所包含的Nj中的电路板数。
  9           由此可知,连接块Nj的连线跨越插槽i和i+1当且仅当now[j]>0且now[j]!=total[j]。用这个条件来计算插槽i和i+1间的连线密度。
 10 
 11           在算法Backtrack中,当i=n时,所有n个电路板都已排定,其密度是cd。由于算法仅完成那些比当前最优解更好的排列,故cd肯定优于bestd,此时应更新bestd。
 12           当i<n时,电路板排列尚未完成。x[1:i-1]是当前扩展点所相应的部分排列,cd是相应的部分排列的密度。在当前部分排列之后加入一块未排定的电路板,扩展当前部分排列产生当前扩展结点的一个儿子结点。
 13           对于这个儿子结点,计算新的部分排列密度ld。仅当ld<bestd时,算法搜索相应子树,否则该子树剪去。
 14 
 15 算法效率:在解空间排列树的每个节点处,算法Backtrack花费O(m)计算时间为每个儿子节点计算密度。因此计算密度所消耗的总计算时间为O(mn!)。
 16           另外,生成排列树需要O(n!)时间。每次更新当前最优解至少使bestd减少1,而算法运行结束时bestd>=0。因此最优解被更新的额次数为O(m)。更新最优解需要O(mn)时间。
 17           综上,解电路板排列问题的回溯算法Backtrack所需要的计算时间为O(mn!)。
 18 
 19 Auther:xymaqingxiang
 20 Time:2014-05-23
 21 */
 22 
 23 //#include "stdafx.h"
 24 #include <iostream>
 25 #include <fstream> 
 26 #include <stdlib.h>
 27 #include <conio.h>
 28 using namespace std;
 29 
 30 int k=0;
 31 
 32 class Board
 33 {
 34     friend int Arrangement(int **B, int n, int m, int bestx[]);
 35     private:
 36         void Backtrack(int i,int cd);
 37         int n,        //电路板数
 38             m,        //连接板数
 39             *x,        //当前解
 40             *bestx,//当前最优解
 41             bestd,  //当前最优密度
 42             *total, //total[j]=连接块j的电路板数
 43             *now,   //now[j]=当前解中所含连接块j的电路板数
 44             **B;    //连接块数组
 45 };
 46 
 47 template <class Type>
 48 inline void Swap(Type &a, Type &b);
 49 
 50 int Arrangement(int **B, int n, int m, int bestx[]);
 51 
 52 int main()
 53 {
 54     int m ,n;
 55     int bestx[9];
 56 
 57     ifstream fin("data.txt"); 
 58 
 59     fin>>m;
 60     fin>>n;
 61     cout<<"m="<<m<<",n="<<n<<endl;
 62     cout<<"N1={4,5,6},N2={2,3},N3={1,3},N4={3,6},N5={7,8}"<<endl;
 63     cout<<"二维数组B如下:"<<endl;
 64     
 65     //构造B
 66     int **B = new int*[n+1];
 67     for(int i=1; i<=n; i++)
 68         B[i] = new int[m+1];
 69 
 70     for(int i=1; i<=n; i++)
 71     {
 72         for(int j=1; j<=m ;j++)
 73         {
 74             fin>>B[i][j];
 75             cout<<B[i][j]<<" ";
 76         }
 77         cout<<endl;
 78     }
 79 
 80     //第一种方案——只打印其中一种最优的电路排列
 81     //cout<<"返回的其中一种最优解:"<<endl;
 82     //cout<<"当前最优密度为:"<<Arrangement(B,n,m,bestx)<<endl;
 83     //cout<<"最优排列为:"<<endl;
 84     //for(int i=1; i<=n; i++)
 85         //cout<<bestx[i]<<" ";
 86     //cout<<endl;
 87 
 88     //第二种方案——打印出所有的最优电路排列
 89     Arrangement(B,n,m,bestx);
 90 
 91     for(int i=1; i<=n; i++)
 92         delete[] B[i];
 93     delete[] B;
 94 
 95     cout<<"总方案数为:"<<k<<endl;
 96     getch();
 97 
 98     return 0;
 99 }
100 
101 void Board::Backtrack(int i,int cd)//回溯法搜索排列树
102 {
103     
104     if(i == n)
105     {
106         cout<<endl;
107         k++;
108         cout<<""<<k<<"种最优密度为:";
109         cout<<cd<<endl;
110         cout<<"最优电路排列为:";
111         for(int i=1; i<=n; i++)
112             cout<<x[i]<<" ";
113         cout<<endl;
114         cout<<endl;
115 
116         for(int j=1; j<=n; j++)
117             bestx[j] = x[j];
118         bestd = cd;
119     }
120     else
121     {
122         for(int j=i; j<=n; j++)
123         {
124             //选择x[j]为下一块电路板
125             int ld = 0;
126             for(int k=1; k<=m; k++)
127             {
128                 now[k] += B[x[j]][k];
129                 if(now[k]>0 && total[k]!=now[k])
130                     ld ++;
131             }
132 
133             //更新ld
134             if(cd>ld)
135                 ld = cd;
136 
137             if(ld<=bestd)//搜索子树————剪枝函数(ld<bestd时只打印其中一种最优排列;ld<=bestd可以打印出所有的最优排列)
138             {
139                 Swap(x[i],x[j]);
140                 Backtrack(i+1,ld);
141                 Swap(x[i],x[j]);
142 
143                 //恢复状态
144                 for(int k=1; k<=m; k++)
145                     now[k] -= B[x[j]][k];
146             }
147         }
148     }    
149 }
150 
151 int Arrangement(int **B, int n, int m, int bestx[])
152 {
153     Board X;
154 
155     //初始化X
156     X.x = new int[n+1];
157     X.total = new int[m+1];
158     X.now = new int[m+1];
159     X.B = B;
160     X.n = n;
161     X.m = m;
162     X.bestx = bestx;
163     X.bestd = m+1;
164 
165     //初始化total和now
166     for(int i=1; i<=m; i++)
167     {
168         X.total[i] = 0;
169         X.now[i] = 0;
170     }
171 
172     //初始化x为单位排列并计算total
173     for(int i=1; i<=n; i++)
174     {
175         X.x[i] = i;
176         for(int j=1; j<=m; j++)
177         {
178             X.total[j] += B[i][j];
179         }
180     }
181 
182     //回溯搜索
183     X.Backtrack(1,0);
184     delete []X.x;
185     delete []X.total;
186     delete []X.now;
187     return X.bestd;
188 }
189 
190 template <class Type>
191 inline void Swap(Type &a, Type &b)
192 {  
193     Type temp=a; 
194     a=b; 
195     b=temp;
196 }
电路板排列问题

 

3、旅行售货员问题:

bubuko.com,布布扣
 1 template<class Type>
 2 class Traveling
 3 {
 4     friend Type TSP(int **,int [],int,Type);
 5     friend void main(void);
 6 public:
 7     Type BBTSP(int v[]);
 8 private:
 9     void Backtrack(int i);
10     int n,               //图G的顶点数
11         *x,              //当前解
12         *bestx;          //当前最优解
13     Type **a,            //图G的邻接矩阵
14          cc,             //当前费用
15          bestc,          //当前最优值
16          NoEdge;         //无边标记
17 };
18 
19 template<class Type>
20 void Traveling<Type>::Backtrack(int i)
21 {
22     if(i==n)
23     {
24         if(a[x[n-1]][x[n]]!=NoEdge&&a[x[n][1]!=NoEdge&&
25             cc+a[x[n-1]][x[n]]+a[x[n]][1]<bestc||bestc==NoEdge))
26             for(int j=1;j<=n;j++)
27                 bestx[j]=x[j];
28         bestc=cc+a[x[n-1]][x[n]]+a[x[n]][1];
29     }
30     else
31     {//是否进入左子树?
32         for(int j=i;j<=n;j++)
33             if(a[x[i-1][x[j]]!=NoEdge&&
34                 (cc+a[x[i-1][x[j]]<bestc||bestc==NoEdge))
35             {
36                 //搜索子树
37                 Swap(x[i],x[j]);
38                 cc+=a[x[i-1][x[i]];
39                 Backtrack(i+1);
40                 cc-=a[x[i-1]][x[i]];
41                 Swap(x[i],x[j]);
42             }
43     }
44 }
45 
46 template<class Type>
47 Type TSP(Type **a,int v[],int n,Type NoEdge)
48 {
49     Traveling<Type> Y;
50     //初始化Y
51     Y.x=new int[n+1];
52     //置x为单位排列
53     for(int i=1;i<=n;i++)
54         Y.x[i]=i;
55     Y.a=a;
56     Y.n=n;
57     Y.bestc=NoEdge;
58     Y.bestx=v;
59     Y.cc=0;
60     Y.NoEdge=NoEdge;
61     //搜索x[2:n]的全排列
62     Y.Backtrack(2);
63     delete []Y.x;
64     return Y.bestc;
65 }
书本模板--C++

 

 

 

 

 

 

 

 

回溯法小实例,布布扣,bubuko.com

回溯法小实例

标签:style   class   blog   code   http   tar   

原文地址:http://www.cnblogs.com/xymqx/p/3747446.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!