标签:style class blog code http tar
1、图的m着色问题:
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 }
2、电路板排列问题:
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、旅行售货员问题:
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 }
标签:style class blog code http tar
原文地址:http://www.cnblogs.com/xymqx/p/3747446.html