分治算法 把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)……
二分搜索
大整数乘法
棋盘覆盖
合并排序
快速排序
线性时间选择
最接近点对问题
循环赛日程表
汉诺塔
分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题 解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题 合并:将各个子问题的解合并为原问题的解。
汉诺塔 如果是有一个盘, A->C 如果我们有 n >= 2 情况,我们总是可以看做是两个盘 1.最下边的盘 2. 上面的盘
先把 最上面的盘 A->B
把最下边的盘 A->C
把B塔的所有盘 从 B->C
1 2 3 4 5 6 7 8 9 10 11 12 public static void hanoiTower (int num,char a ,char b, char c) { if (num == 1 ){ System.out.println("第1个盘从 " +a+"->" +c); }else { hanoiTower(num-1 ,a,c,b); System.out.println("第" +num+"个盘从 " +a+"->" +c); hanoiTower(num-1 ,b,a,c); } }
动态规划 动态规划(Dynamic Programming)算法的核心思想是:将大问题划分为小问题进行解决,从而一步步获取最优解的处理算法
动态规划算法与分治算法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。
与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。 ( 即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解 )
动态规划可以通过填表的方式来逐步推进,得到最优解.
背包问题 有一个背包,容量为4磅 , 现有如下物品
物品
重量
价格
a
1
1500
b
4
3000
c
3
2000
要求达到的目标为装入的背包的总价值最大,并且重量不超出 要求装入的物品不能重复
算法的主要思想,利用动态规划来解决。每次遍历到的第i个物品,根据w[i]和v[i]来确定是否需要将该物品放入背包中。即对于给定的n个物品,设v[i]、w[i]分别为第i个物品的价值和重量,C为背包的容量。再令v[i][j]表示在前i个物品中能够装入容量为j的背包中的最大价值。则我们有下面的结果:
物品
0
1
2
3
4
0
0
0
0
0
a
0
1500(a)
1500(a)
1500(a)
1500(a)
b
0
1500(a)
1500(a)
1500(a)
3000(b)
c
0
1500(a)
1500(a)
2000(c)
3500(a+c)
1 2 3 4 5 6 7 8 9 (1) v[i][0]=v[0][j]=0; //表示 填入表 第一行和第一列是0 (2) 当w[i]> j 时:v[i][j]=v[i-1][j] // 当准备加入新增的商品的容量大于 当前背包的容量时,就直接使用上一个单元格的装入策略 (3) 当j>=w[i]时: v[i] [j]=max{v[i-1][j], v[i]+v[i-1][j-w[i]]} // 当 准备加入的新增的商品的容量小于等于当前背包的容量, // 装入的方式: v[i-1][j]: 就是上一个单元格的装入的最大值 v[i] : 表示当前商品的价值 v[i-1][j-w[i]] : 装入i-1商品,到剩余空间j-w[i]的最大值 当j>=w[i]时: v[i][j]=max{v[i-1][j], v[i]+v[i-1][j-w[i]]} :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 public static void main (String[] args) { int [] w = {1 , 4 , 3 }; int [] val = {1500 , 3000 , 2000 }; int m = 4 ; int n = val.length; int [][] v = new int [n+1 ][m+1 ]; int [][] path = new int [n+1 ][m+1 ]; for (int i = 0 ; i < v.length; i++) { v[i][0 ] = 0 ; } for (int i=0 ; i < v[0 ].length; i++) { v[0 ][i] = 0 ; } for (int i = 1 ; i < v.length; i++) { for (int j=1 ; j < v[0 ].length; j++) { if (w[i-1 ]> j) { v[i][j]=v[i-1 ][j]; } else { if (v[i - 1 ][j] < val[i - 1 ] + v[i - 1 ][j - w[i - 1 ]]) { v[i][j] = val[i - 1 ] + v[i - 1 ][j - w[i - 1 ]]; path[i][j] = 1 ; } else { v[i][j] = v[i - 1 ][j]; } } } } for (int i =0 ; i < v.length;i++) { for (int j = 0 ; j < v[i].length;j++) { System.out.print(v[i][j] + " " ); } System.out.println(); } System.out.println("============================" ); int i = path.length - 1 ; int j = path[0 ].length - 1 ; while (i > 0 && j > 0 ) { if (path[i][j] == 1 ) { System.out.printf("第%d个商品放入到背包\n" , i); j -= w[i-1 ]; } i--; } }
KMP算法 暴力匹配 现在str1匹配到 i 位置,子串str2匹配到 j 位置,则有:
如果当前字符匹配成功(即str1[i] == str2[j]),则i++,j++,继续匹配下一个字符
如果失配(即str1[i]! = str2[j]),令i = i - (j - 1),j = 0。相当于每次匹配失败时,i 回溯,j 被置为0。
用暴力方法解决的话就会有大量的回溯,每次只移动一位,若是不匹配,移动到下一位接着判断,浪费了大量的时间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public static int violenceMatch (String str1, String str2) { char [] s1 = str1.toCharArray(); char [] s2 = str2.toCharArray(); int s1Len = s1.length; int s2Len = s2.length; int i = 0 ; int j = 0 ; while ( i < s1Len && j<s2Len){ if (s1[i]==s2[j]){ i++; j++; }else { i = i-(j-1 ); j = 0 ; } } if (j == s2Len){ return i - j; }else { return -1 ; } }
KMP算法
KMP方法算法就利用之前判断过信息,通过一个next数组,保存模式串中前后最长公共子序列的长度 ,每次回溯时,通过next数组找到,前面匹配过的位置,省去了大量的计算时间
https://www.cnblogs.com/ZuoAndFutureGirl/p/9028287.html
字符串 bread
前缀 b br bre ,brea
后缀d ed ead read
abcda 前缀 a ab abc abcd 后缀 bcda ,cda,da,a 共有长度为1
完成部分匹配表
使用部分匹配表匹配字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 next数组每次 ABABCABAA 001201231 AB ABC A 最长为1 要让下一位匹配 只用判断下一位是不是B就可以了 如果相同 len++; next[i] = len; 如果不相同 需要向前进行比较比 len = next[len-1 ] public static int kmpSearch (String str1, String str2, int [] next) { for (int i = 0 , j = 0 ; i < str1.length(); i++) { while ( j > 0 && str1.charAt(i) != str2.charAt(j)) { j = next[j-1 ]; } if (str1.charAt(i) == str2.charAt(j)) { j++; } if (j == str2.length()) { return i - j + 1 ; } } return -1 ; } public static int [] kmpNext(String dest) { int [] next = new int [dest.length()]; next[0 ] = 0 ; int i = 1 ; int len = 0 ; while (i<dest.length()){ if (dest.charAt(i) == dest.charAt(len)){ len++; next[i] = len; i++; }else { if (len > 0 ){ len = next[len - 1 ]; }else { next[i] = len; i++; } } } return next; }
贪心算法 在每一步选择中都采取最好或者最优(即最有利)的选择,从而希望能够导致结果是最好或者最优的算法.
不一定是最优的结果(有时候会是最优解)
集合覆盖问题 假设存在下面需要付费的广播台,以及广播台信号可以覆盖的地区。 如何选择最少的广播台,让所有的地区都可以接收到信号
广播台
覆盖地区
K1
“北京”, “上海”, “天津”
K2
“广州”, “北京”, “深圳”
K3
“成都”, “上海”, “杭州”
K4
“上海”, “天津”
K5
“杭州”, “大连”
1 2 3 遍历所有的广播电台, 找到一个覆盖了最多未覆盖的地区的电台(此电台可能包含一些已覆盖的地区,但没有关系) 将这个电台加入到一个集合中(比如ArrayList), 想办法把该电台覆盖的地区在下次比较时去掉。 重复第1 步直到覆盖了全部的地区
普里姆算法 有胜利乡有7个村庄(A, B, C, D, E, F, G) ,现在需要修路把7个村庄连通 各个村庄的距离用边线表示(权) ,比如 A – B 距离 5公里 问:如何修路保证各个村庄都能连通,并且总的修建公路总里程最短?
最小生成树 :普里姆算法和克鲁斯卡尔算法
1 2 3 4 5 1.设G=(V,E)是连通网,T=(U,D)是最小生成树,V,U是顶点集合,E,D是边的集合 2.若从顶点u开始构造最小生成树,则从集合V中取出顶点u放入集合U中,标记顶点v的visited[u]=1 3.若集合U中顶点ui与集合V-U中的顶点vj之间存在边,则寻找这些边中权值最小的边,但不能构成回路,将顶点vj加入集合U中,将边(ui,vj)加入集合D中,标记visited[vj]=1 4.重复步骤②,直到U与V相等,即所有顶点都被标记为访问过,此时D中有n-1条边
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 public class Prim { public static final int MAX = 10000 ; public static void main (String[] args) { char [] data = new char []{'A' ,'B' ,'C' ,'D' ,'E' ,'F' ,'G' }; int verxs = data.length; int [][]weight=new int [][]{ {0 ,5 ,7 ,10000 ,10000 ,10000 ,2 }, {5 ,0 ,10000 ,9 ,10000 ,10000 ,3 }, {7 ,10000 ,0 ,10000 ,8 ,10000 ,10000 }, {10000 ,9 ,10000 ,0 ,10000 ,4 ,10000 }, {10000 ,10000 ,8 ,10000 ,0 ,5 ,4 }, {10000 ,10000 ,10000 ,4 ,5 ,0 ,6 }, {2 ,3 ,10000 ,10000 ,4 ,6 ,0 },}; MGraph graph = new MGraph(verxs); MinTree minTree = new MinTree(); minTree.createGraph(graph, verxs, data, weight); minTree.showGraph(graph); minTree.prim(graph); } } class MinTree { public static final int MAX = 10000 ; public void createGraph (MGraph graph, int verxs, char data[], int [][] weight) { int i, j; for (i = 0 ; i < verxs; i++) { graph.data[i] = data[i]; for (j = 0 ; j < verxs; j++) { graph.weight[i][j] = weight[i][j]; } } } public void showGraph (MGraph graph) { for (int [] link: graph.weight) { System.out.println(Arrays.toString(link)); } } public void prim (MGraph graph) { int [] lowcost = new int [graph.verxs]; int [] mst = new int [graph.verxs]; int min = 0 ; int minid; int sum = 0 ; for (int i = 1 ; i < graph.verxs; i++){ lowcost[i] = graph.weight[0 ][i]; mst[i] = 0 ; } for (int i = 1 ; i < graph.verxs; i++){ min = MAX; minid = 0 ; for (int j = 1 ;j<graph.verxs; j++){ if (lowcost[j]<min && lowcost[j] != 0 ){ min = lowcost[j]; minid = j; } } System.out.println(graph.data[mst[minid]] + "到" + graph.data[minid] + " 权值:" + min); sum += min; lowcost[minid] = 0 ; for (int j = 0 ;j<graph.verxs;j++){ if (graph.weight[minid][j] < lowcost[j]){ lowcost[j] = graph.weight[minid][j]; mst[j] = minid; } } } System.out.println("sum:" +sum); } } class MGraph { int verxs; char [] data; int [][] weight; public MGraph (int verxs) { this .verxs = verxs; data = new char [verxs]; weight = new int [verxs][verxs]; } }
克鲁斯卡尔 先构造一个只含n个顶点的森林,然后依权值从小到大从连通网中选择边加入到森林中,并使森林中不产生回路,直至森林变成一棵树为止
1) 就是将所有顶点按照从小到大的顺序排列好之后;某个顶点的终点就是”与它连通的最大顶点”。
我们加入的边的两个顶点不能都指向同一个终点,否则将构成回路。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 public class Kruskal { private int edgeNum; private char [] vertexs; private int [][] matrix; private static final int INF = Integer.MAX_VALUE; public static void main (String[] args) { char [] vertexs = {'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' }; int matrix[][] = { { 0 , 12 , INF, INF, INF, 16 , 14 }, { 12 , 0 , 10 , INF, INF, 7 , INF}, { INF, 10 , 0 , 3 , 5 , 6 , INF}, { INF, INF, 3 , 0 , 4 , INF, INF}, { INF, INF, 5 , 4 , 0 , 2 , 8 }, { 16 , 7 , 6 , INF, 2 , 0 , 9 }, { 14 , INF, INF, INF, 8 , 9 , 0 }}; Kruskal kruskalCase = new Kruskal(vertexs, matrix); kruskalCase.print(); kruskalCase.kruskal(); } public Kruskal (char [] vertexs, int [][] matrix) { int vlen = vertexs.length; this .vertexs = new char [vlen]; for (int i = 0 ; i < vertexs.length; i++) { this .vertexs[i] = vertexs[i]; } this .matrix = new int [vlen][vlen]; for (int i = 0 ; i < vlen; i++) { for (int j= 0 ; j < vlen; j++) { this .matrix[i][j] = matrix[i][j]; } } for (int i =0 ; i < vlen; i++) { for (int j = i+1 ; j < vlen; j++) { if (this .matrix[i][j] != INF) { edgeNum++; } } } } public void kruskal () { int index = 0 ; int [] ends = new int [edgeNum]; EData[] rets = new EData[edgeNum]; EData[] edges = getEdges(); Arrays.sort(edges); for (int i = 0 ; i<edgeNum; i++){ int p1 = getPosition(edges[i].start); int p2 = getPosition(edges[i].end); int m = getEnd(ends, p1); int n = getEnd(ends, p2); if (m != n){ ends[m] = n; rets[index++] = edges[i]; } } System.out.println("最小生成树为" ); for (int i = 0 ; i < index; i++) { System.out.println(rets[i]); } } public void print () { System.out.println("邻接矩阵为: \n" ); for (int i = 0 ; i < vertexs.length; i++) { for (int j=0 ; j < vertexs.length; j++) { System.out.printf("%12d" , matrix[i][j]); } System.out.println(); } } private int getPosition (char ch) { for (int i = 0 ; i < vertexs.length; i++) { if (vertexs[i] == ch) { return i; } } return -1 ; } private EData[] getEdges() { int index = 0 ; EData[] edges = new EData[edgeNum]; for (int i = 0 ; i < vertexs.length; i++) { for (int j=i+1 ; j <vertexs.length; j++) { if (matrix[i][j] != INF) { edges[index++] = new EData(vertexs[i], vertexs[j], matrix[i][j]); } } } return edges; } private int getEnd (int [] ends, int i) { while (ends[i] != 0 ) { i = ends[i]; } return i; } } class EData implements Comparable <EData > { char start; char end; int weight; public EData (char start, char end, int weight) { this .start = start; this .end = end; this .weight = weight; } @Override public String toString () { return "EData [<" + start + ", " + end + ">= " + weight + "]" ; } @Override public int compareTo (EData o) { return this .weight - o.weight; } }
prim算法适合稠密图,kruskal算法适合稀疏图。
prim O(n2)
kruskal O(nlogn)
迪杰斯特拉 Dijkstra O(n²)
以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。
1 2 3 4 设置出发顶点为v,顶点集合V{v1,v2,vi...},v到V中各顶点的距离构成距离集合Dis,Dis{d1,d2,di...},Dis集合记录着v到图中各顶点的距离(到自身可以看作0,v到vi距离对应为di) 1.从Dis中选择值最小的di并移出Dis集合,同时移出V集合中对应的顶点vi,此时的v到vi即为最短路径 2.更新Dis集合,更新规则为:比较v到V集合中顶点的距离值,与v通过vi到V集合中顶点的距离值,保留值较小的一个(同时也应该更新顶点的前驱节点为vi,表明是通过vi到达的) 3.重复执行两步骤,直到最短路径顶点为目标顶点即可结束
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 public class Dijkstra { public static void main (String[] args) { char [] vertex = { 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' }; int [][] matrix = new int [vertex.length][vertex.length]; final int N = 65535 ; matrix[0 ]=new int []{N,5 ,7 ,N,N,N,2 }; matrix[1 ]=new int []{5 ,N,N,9 ,N,N,3 }; matrix[2 ]=new int []{7 ,N,N,N,8 ,N,N}; matrix[3 ]=new int []{N,9 ,N,N,N,4 ,N}; matrix[4 ]=new int []{N,N,8 ,N,N,5 ,4 }; matrix[5 ]=new int []{N,N,N,4 ,5 ,N,6 }; matrix[6 ]=new int []{2 ,3 ,N,N,4 ,6 ,N}; Graph graph = new Graph(vertex, matrix); graph.showGraph(); graph.dsj(0 ); graph.showDijkstra(); } } class Graph { private char [] vertex; private int [][] matrix; private VisitedVertex vv; public Graph (char [] vertex, int [][] matrix) { this .vertex = vertex; this .matrix = matrix; } public void showDijkstra () { vv.show(); } public void showGraph () { for (int [] link : matrix) { System.out.println(Arrays.toString(link)); } } public void dsj (int index) { vv = new VisitedVertex(vertex.length, index); update(index); for (int j = 1 ; j <vertex.length; j++) { index = vv.updateArr(); update(index); } } private void update (int index) { int len = 0 ; for (int j = 0 ; j < matrix[index].length; j++) { len = vv.getDis(index) + matrix[index][j]; if (!vv.in(j) && len < vv.getDis(j)) { vv.updatePre(j, index); vv.updateDis(j, len); } } } } class VisitedVertex { public int [] already_arr; public int [] pre_visited; public int [] dis; public VisitedVertex (int length, int index) { this .already_arr = new int [length]; this .pre_visited = new int [length]; this .dis = new int [length]; Arrays.fill(dis, 65535 ); this .already_arr[index] = 1 ; this .dis[index] = 0 ; } public boolean in (int index) { return already_arr[index] == 1 ; } public void updateDis (int index, int len) { dis[index] = len; } public void updatePre (int pre, int index) { pre_visited[pre] = index; } public int getDis (int index) { return dis[index]; } public int updateArr () { int min = 65535 , index = 0 ; for (int i = 0 ; i < already_arr.length; i++) { if (already_arr[i] == 0 && dis[i] < min ) { min = dis[i]; index = i; } } already_arr[index] = 1 ; return index; } public void show () { System.out.println("==========================" ); for (int i : already_arr) { System.out.print(i + " " ); } System.out.println(); for (int i : pre_visited) { System.out.print(i + " " ); } System.out.println(); for (int i : dis) { System.out.print(i + " " ); } System.out.println(); char [] vertex = { 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' }; int count = 0 ; for (int i : dis) { if (i != 65535 ) { System.out.print(vertex[count] + "(" +i+") " ); } else { System.out.println("N " ); } count++; } System.out.println(); } }
弗洛伊德 弗洛伊德(Floyd):计算图中各个顶点之间的最短路径
弗洛伊德算法中每一个顶点都是出发访问点,所以需要将每一个顶点看做被访问顶点,求出从每一个顶点到其他顶点的最短路径。
1 2 3 4 5 6 7 8 1.设置顶点vi到顶点vk的最短路径已知为Lik,顶点vk到vj的最短路径已知为Lkj,顶点vi到vj的路径为Lij,则vi到vj的最短路径为:min((Lik+Lkj),Lij),vk的取值为图中所有顶点,则可获得vi到vj的最短路径 2.至于vi到vk的最短路径Lik或者vk到vj的最短路径Lkj,是以同样的方式获得 2张表 ,一张是前驱节点,一张是距离 1.通俗讲,就是讲这个顶点作为中间顶点计算所有顶点的最低路径 2.每次更换中间节点,遍历,最后得出结果 中间顶点 [A,B,C,D,E] K 出发顶点 [A,B,C,D,E] i 终点 [A,B,C,D,E] j
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 public class Floyd { public static void main (String[] args) { char [] vertex = { 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' }; int [][] matrix = new int [vertex.length][vertex.length]; final int N = 65535 ; matrix[0 ] = new int [] { 0 , 5 , 7 , N, N, N, 2 }; matrix[1 ] = new int [] { 5 , 0 , N, 9 , N, N, 3 }; matrix[2 ] = new int [] { 7 , N, 0 , N, 8 , N, N }; matrix[3 ] = new int [] { N, 9 , N, 0 , N, 4 , N }; matrix[4 ] = new int [] { N, N, 8 , N, 0 , 5 , 4 }; matrix[5 ] = new int [] { N, N, N, 4 , 5 , 0 , 6 }; matrix[6 ] = new int [] { 2 , 3 , N, N, 4 , 6 , 0 }; Graph graph = new Graph(vertex.length, matrix, vertex); graph.floyd(); graph.show(); } } class Graph { private char [] vertex; private int [][] dis; private int [][] pre; public Graph (int length, int [][] matrix, char [] vertex) { this .vertex = vertex; this .dis = matrix; this .pre = new int [length][length]; for (int i = 0 ; i < length; i++) { Arrays.fill(pre[i], i); } } public void show () { char [] vertex = { 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' }; for (int k = 0 ; k < dis.length; k++) { for (int i = 0 ; i < dis.length; i++) { System.out.print(vertex[pre[k][i]] + " " ); } System.out.println(); for (int i = 0 ; i < dis.length; i++) { System.out.print("(" +vertex[k]+"到" +vertex[i]+"的最短路径是" + dis[k][i] + ") " ); } System.out.println(); System.out.println(); } } public void floyd () { int len = 0 ; for (int k = 0 ;k < dis.length;k++){ for (int i = 0 ; i < dis.length; i++){ for (int j = 0 ; j < dis.length; j++){ len = dis[i][k] + dis[k][j]; if (len < dis[i][j]){ dis[i][j] = len; pre[i][j] = pre[k][j]; } } } } } }
马踏棋盘算法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 public class HorseChessboard { private static int X ; private static int Y ; private static boolean visited[]; private static boolean finished; public static void main (String[] args) { X = 8 ; Y = 8 ; int row = 1 ; int column = 1 ; int [][] chessboard = new int [X][Y]; visited = new boolean [X * Y]; long start = System.currentTimeMillis(); traversalChessboard(chessboard, row - 1 , column - 1 , 1 ); long end = System.currentTimeMillis(); System.out.println("共耗时: " + (end - start) + " 毫秒" ); for (int [] rows : chessboard) { for (int step: rows) { System.out.print(step + "\t" ); } System.out.println(); } } public static void traversalChessboard (int [][] chessboard, int row, int column, int step) { chessboard[row][column] = step; visited[row * X + column] = true ; ArrayList<Point> ps = next(new Point(column, row)); sort(ps); while (!ps.isEmpty()){ Point p = ps.remove(0 ); if (!visited[p.y * X + p.x]) { traversalChessboard(chessboard, p.y, p.x, step + 1 ); } } if (step < X * Y && !finished ) { chessboard[row][column] = 0 ; visited[row * X + column] = false ; } else { finished = true ; } } public static ArrayList<Point> next (Point curPoint) { ArrayList<Point> ps = new ArrayList<Point>(); Point p1 = new Point(); if ((p1.x = curPoint.x - 2 ) >= 0 && (p1.y = curPoint.y -1 ) >= 0 ) { ps.add(new Point(p1)); } if ((p1.x = curPoint.x - 1 ) >=0 && (p1.y=curPoint.y-2 )>=0 ) { ps.add(new Point(p1)); } if ((p1.x = curPoint.x + 1 ) < X && (p1.y = curPoint.y - 2 ) >= 0 ) { ps.add(new Point(p1)); } if ((p1.x = curPoint.x + 2 ) < X && (p1.y = curPoint.y - 1 ) >= 0 ) { ps.add(new Point(p1)); } if ((p1.x = curPoint.x + 2 ) < X && (p1.y = curPoint.y + 1 ) < Y) { ps.add(new Point(p1)); } if ((p1.x = curPoint.x + 1 ) < X && (p1.y = curPoint.y + 2 ) < Y) { ps.add(new Point(p1)); } if ((p1.x = curPoint.x - 1 ) >= 0 && (p1.y = curPoint.y + 2 ) < Y) { ps.add(new Point(p1)); } if ((p1.x = curPoint.x - 2 ) >= 0 && (p1.y = curPoint.y + 1 ) < Y) { ps.add(new Point(p1)); } return ps; } public static void sort (ArrayList<Point> ps) { ps.sort(new Comparator<Point>() { @Override public int compare (Point o1, Point o2) { int count1 = next(o1).size(); int count2 = next(o2).size(); if (count1 < count2){ return -1 ; }else if (count1 == count2){ return 0 ; }else { return 1 ; } } }); } }