intpartition(Type a[], int p, int r){ int i = p, j = r+1 Type x = a[p] //第一个元素为基准 while (true) { while (a[++i] < x && i < r) //左标兵向右 while (a[--j] > x) //右标兵向左 if (i >= j) break swap(a[i], a[j]) //交换位置 } a[p] = a[j] //第一个元素和最小数交换位置 a[j] = x return j //返回基准位置 }
intrandomizedPartition (Type a[], int p, int r) { int i = random(p, r) swap(a[i], a[p]) //将随机元素作为基准(第一个元素) returnpartition(a, p, r) }
Type randomizedSelect(Type a[], int p, int r, int k) { //第k小个元素 if (p == r) //只有一个元素 return a[p] int i = randomizedPartition(a, p ,r) //i为随机基准位置 j = i-p+1//计算数组a[p:i]个数(左边) if (k <= j) returnrandomizedSelect(a, p, i, k) //落在左边 else returnrandomizedSelect(a, i+1, r, k-j) //落在右边 }
voidknapsack(Type v, int w, int c, int n, Type **m){ //价值,重量,容量,数量,矩阵 int jMax = min(w[n]-1, c) for (int j = 0; j <= jMax; j++) m[n][j] = 0 for (int j = w[n]; j <= c; j++) m[n][j] = v[n] for (int i = n-1; i > 1; i==) { jMax = min(w[i] - 1, c) for (int j = 0; j <= jMax; j++) m[i][j] = m[i+1][j] for (int j =w [i]; j <= c; j++) m[i][j] = max(m[1][c], m[2][c-w[1]]+v[i]) m[1][c] = m[2][c] if (c >= w[1]) m[1][c] = max(m[1][c], m[2][c-w[1]]+v[1]) } }
// 01背包问题,动态规划,O(n)
var knapsack = { getMaxValue: function (weight, value, n, w) { //各物品重量,各物品价值,物品数量,背包容量 var table = newArray(n) for (var i = 0; i < table.length; i++) { table[i] = newArray(w) for (var j = 0; j < table[i].length; j++) table[i][j] = 0 } for (var i = 1; i < n; i++) { //物品数量 for (var j = 1; j < w; j++) { //背包容量 if (weight[i] > j) table[i][j] = table[i - 1][j] //装不下(物品价值大于背包容量) else table[i][j] = Math.max(table[i - 1][j], table[i - 1][j - weight[i]] + value[i]) //装得下(max{装,不装}) } } return table[n-1][w-1] }, main: function () { var weight = newArray(6, 3, 5, 4, 6) var value = newArray(2, 2, 6, 5, 4) var n = 5, w = 10 returnthis.getMaxValue(weight, value, n, w) } } console.log(knapsack.main())
回溯法
n皇后问题
boolplace(int t){ for (int i; i < t; i++) if ((x[i] == x[t]) || (abs(t-i) == abs(x[t]-x[i]))) returnfalse returntrue }
voidbacktrack(int t) { if (t > n) sum++ else { for (int i; i < n; i++) { x[t] = i //关键 if (place(t)) backtrack(t+1) } } }
//n皇后问题,回溯法
var n = 4 var x = [] functionplace(t) { //判断第t个皇后能否放在第i个位置 var flag = true for (var j = 0; j < t; j++) { if (x[t] === x[j] || t - j === Math.abs(x[t] - x[j])) { //判断与竖、撇捺是否有冲突 flag = false break } } return flag } functionbacktrack(t) { if (t === n) { //当前位置到了叶节点输出一个解 console.log(x) } else { for (var i = 0; i < n; i++) { x[t] = i if (place(t)) { queen(t + 1) //不冲突进行下一行搜索 } } } } backtrack(0)
贪心算法
最小生成树
O(n^2)
MST性质(最小生成树定义):假设G=(V, E)是一个连通网,U 是顶点集V的真子集。若(u, v )是一条具有最小权值的边,其中u∈U, v∈V-U,则必存在一棵包含边(u, v)的最小生成树。
voidprim(int n, Type **c){ Type lowcost[maxint] int closet[maxint] bool s[maxint] s[1] = true for (int i = 2; i <= n; i++) { lowcost[i] = c[1][i] closet[i] = 1 s[i] = false } for (int i = 1; i < n; i++) { Type min = INF int j = 1 for (int k = 2; k <= n; k++) { if ((lowcost[k] < min) && (!s[k])) { min = lowcost[k] j = k } } s[j] = true for (int k = 2; k <= n; k++) { if ((c[j][k] < lowcost(k)) && (!s[k])) { lowcost[k] = c[j][k] closet[k] = j } } } }
//最小生成树,prim算法(伪代码)
functionprim(int n, int u0, int c[N][N]) { s[u0] = true//第一个点在U内 //初始化 for (int i; i < n; i++) { if (i !== u0) { lowcost[i] = c[u0][i] //最近权为到u0的权 closet[i] = u0 //最近点为u0 s[i] = false//不在U内 } else { lowcost[i] = 0 } } for (int i = 1; i < n; i++) { int temp = INF //权 int t = u0 for (int j = 1; j < n; j++) { if ((!s[j]) && (lowcost[j] < temp)) { //不在U内且权更小 t = j temp = lowcost[j] } } if (t === u0) //找不到最小路径点 break s[t] = true//加入U //更新lowcost和closet for (int j = 1; j <= n; j++) { if ((!s[j]) && (c[t][j] < lowcost[j])) { //不在U内且t到j的权小于最短权 lowcost[j] = c[t][j] closest[j] = t } } } //最小费用为lowcost之和 }