子集合问题
求集合S的所有子集合(不包括空集),可以按照框架一的算法写代码。
1 #include<iostream> 2 using namespace std; 3 int s[4]={3,5,7,9}; 4 int x[4]; 5 int N=4; 6 7 void print() { 8 for(int j=0;j<N;j++) 9 if(x[j]==1) 10 cout<<s[j]<<" "; 11 cout<<endl; 12 } 13 14 void SubSet(int i) { 15 if(i>=N) { 16 print(); 17 return; 18 } 19 x[i]=1; 20 SubSet(i+1); 21 x[i]=0; 22 SubSet(i+1); 23 } 24 int main() { 25 cout<<"数组的子集合为: "<<endl; 26 SubSet(0); 27 return 0; 28 }
在此基础上,求解有条件限制的子集合问题,例如,整数集合s和一个整数sum,求集合s的所有子集su,使得su的元素之和等于sum。
#include <stdio.h> int flag,sum=0; int *s, *x, n,c; void backtrack(int t) { int i; if(t==n) { if(sum==c) { flag=1; for(i=0;i<n;i++) if(x[i]) printf("%3d",s[i]); printf(" "); return; } } else { sum+=s[t]; x[t]=1; backtrack(t+1); x[t]=0; sum-=s[t]; backtrack(t+1); } } int main() { int i; scanf("%d%d",&n,&c); s=new int [n]; x=new int[n]; for(i=0;i<n;i++){ scanf("%d",&s[i]); x[i]=0; } backtrack(0); if(flag) printf("yes"); else printf("no"); return 0; }
相关资料可以看子集和问题
回溯法解决子集和问题http://blog.sina.com.cn/s/blog_7865b083010100dd.html
全排列问题
求一个集合元素的全排列,可以按照框架二写出代码
#include<iostream> using namespace std; int a[4]={3,5,7,9}; const int N=4; void print() { for(int i=0;i<N;i++) cout<<a[i]<<" "; cout<<endl; } void swap(int *a,int i,int j) { int temp; temp=a[i]; a[i]=a[j]; a[j]=temp; } void backtrack(int i) { if(i>=N) { print(); } for(int j=i;j<N;j++) { swap(a,i,j); backtrack(i+1); swap(a,i,j); } } int main() { cout<<"所有组合为: "<<endl; backtrack(0); return 0; }
八皇后问题
(1)定义问题的解空间。这个问题解空间就是8个皇后在棋盘上的位置、
(2)定义解空间的结构。可以使用8*8的数组,但由于任意两个皇后都不能再同行,可以用数组下标表示行,数组的值来表示数组的列,可以简化为一个一维数组x[9];
(3)以深度优先方式搜索解空间,并在搜索过程使用剪枝函数来剪枝。根据条件x[i]==x[k]判断处于同一列,abs(k-i)==abs(x[k]-x[i])判断是否处于同一斜线,剪枝函数如下:
bool canPlace(int k) { for(int i=1;i<k;i++) { if(x[i]==x[k] || abs(k-i)==abs(x[k]-x[i])) return false; } return true; }
按照回溯框架一,八皇后回溯代码如下:
void queue(int i) { if(i>8) { print(); return; } for(int j=1;j<=8;j++) { x[i]=j;//记录所放的列 if(calPlace(i)) queue(i+1); } }
完整代码:
#include<iostream> #include<cmath> using namespace std; int x[9]; int count=1; void print() { cout<<count<<":"; for(int i=1;i<=8;i++) cout<<x[i]<<" "; cout<<endl; count++; } bool canPlace(int k) { for(int i=1;i<k;i++) { if(x[i]==x[k] || abs(k-i)==abs(x[k]-x[i])) return false; } return true; } void queue(int i) { if(i>8) { print(); return; } for(int j=1;j<=8;j++) { x[i]=j;//记录所放的列 if(canPlace(i)) queue(i+1); } } int main() { queue(1); return 0; }
0-1背包问题
问题:给定n种物品和一背包。物品i的重点是Wi,其价值是ui,背包的容量是C。如何选择装入背包的物品,使得装入背包中物品的总价值最大、
0-1背包是子集合选取问题,问题分析步骤如下:
(1)确定解空间。即确定装入何种物品、
(2)确定易于搜索的解空间结构。可以用数组p,w分别表示各个物品价值和重量。
用数组x记录,是否选中物品。
(3)以深度优先方式搜索解空间,并在搜索的过程中剪枝。