for (a = 1; a <= 20; a++) for (b = 1; b <= 33; b++) { if ((100 - a - b) % 3 == 0&&(5 * a + 3 * b + (100 - a - b) / 3 == 100)) { printf("%d %d %d\n", a, b, 100-a-b); } }
回溯法
Backtracking
基本思想
深度优先策略(DFS)
图的遍历(dfs)
DFS实现
像下面的图,要考虑图的连通性
伪代码
1 2 3 4 5 6 7 8 9 10 11 12
procedure explore(G,v) visited[v] = true for each edge (v,u) in E: if not visited[u]: explore(G,u)
procedure dfs(G) for all v in V: visited[v] = false for all v in V: if not visited[v]: explore(G,v)
核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
//C[ ][ ]是图的邻接矩阵,visited[i]表示顶点i是否被访问过 For (i=0;i<=n-1;i++) // n个顶点标志位初始化 visited[i]=0; DFSk (Graph g, int k) //对图g的顶点K进行深度遍历 { visited[k]=1; visit k; for (i=0;i<=n-1;i++) if (g.c[k][i]==1 && visited[i]==0) DFSk(g,i); } DFS (Graph g) //考虑g的连通性 { for (i=0;i<=n-1,i++) if (visited[i]==0) DFSk(g,i); }
背包问题
01背包问题—物体不可分割
普通背包问题—物体可分割
回溯法求解01背包问题
子集树和排列树
子集树:0-1背包问题
排列树: 旅行售货员问题
剪枝函数
剪枝函数优化01背包问题
核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
privatestaticvoidbacktrack(int i) {// 搜索第i层结点 if (i > n) // 到达叶结点 更新最优解bestx,bestw;return; r -= w[i]; if (cw + w[i] <= c) {// 搜索左子树 背包还能装的下 x[i] = 1; cw += w[i]; backtrack(i + 1); cw -= w[i]; } if (cw + r > bestw) { x[i] = 0; // 搜索右子树 后面价值更高,放弃某件物品 backtrack(i + 1); } r += w[i]; }
剪枝函数优化旅行售货员问题
8皇后问题
方法一
若不考虑约束条件,每个皇后都可以尝试放在64个方格中,可以用简单穷举算法,构造如下:
1 2 3 4 5 6 7
for p1:=1 to 64 do for p2:=1 to 64 do for p3:=1 to 64 do for p8:=1 to 64 do if(任意两个皇后满足不在同一行、同一列、同一斜线上) then 输出该摆放方法
Procedure Try(I:integer);{搜索第I行皇后的位置} var j:integer; begin if I=n+1 then 输出方案; for j:=1 to n do if 皇后能放在第I行第J列的位置 then begin 放置第I个皇后; 对放置皇后的位置进行标记; Try(I+1) 对放置皇后的位置释放标记; End; End;
解向量:(x1, x2, … , xn)
显约束:xi=1,2, … ,n
隐约束:
不同列:xi != xj
不处于同一正、反对角线:|i-j|!=|xi-xj|
1 2 3 4 5 6 7 8 9 10 11 12 13
privatestatic boolean place(int k){ for (int j=1;j<k;j++) if ((Math.abs(k-j)==Math.abs(x[j]-x[k]))||(x[j]==x[k])) returnfalse; returntrue; } privatestaticvoidbacktrack(int t){ if (t>n) sum++; //sum是可行方案的个数 else for (int i=1;i<=n;i++) { x[t]=i; if (place(t)) backtrack(t+1); } }