因为这学期上算法课,因为要准备蓝桥杯国赛,所以复习记录一下几个经典的算法 (T_T)。。。
1.Levenshtein编辑距离DP算法
/**
* @author: cuttle
* @Date: 2020/10/21 19:42
* @Description: Levenshetein编辑距离DP算法
*/
public class DP_Levenshtein {
private String A;
private String B;
private int[][] levAB;//记录编辑距离最优解
private char[][] dir;//记录最优解的来源L U A
private int aL;//字符串A的长度
private int bL;//字符串B的长度
private String maxSubString;
private int maxSubStringLen;
StringBuffer aa = new StringBuffer();
StringBuffer bb = new StringBuffer();
public DP_Levenshtein(String A, String B){
this.A = A;
this.B = B;
aL = A.length();
bL = B.length();
levAB = new int[aL + 1][bL + 1];
dir = new char[aL + 1][bL + 1];
}
public void getLSEditDist(){
for(int i = 0;i <= aL;i++){
for(int j = 0;j <= bL;j++){
if(i == 0 || j == 0){
levAB[i][j] = (i >= j ? i : j);
}else{
int d1 = levAB[i - 1][j] + 1;
int d2 = levAB[i][j - 1] + 1;
int d3 = levAB[i - 1][j - 1] + 1;
if(A.charAt(i - 1) == B.charAt(j - 1)){
d3 -= 1;
}
int temp = (d1 > d2 ? d2 : d1);
int min = (temp > d3 ? d3 : temp);
levAB[i][j] = min;
if(min == d2){
dir[i][j] = 'L';//左方
}else if(min == d1){
dir[i][j] = 'U';//上方
}else{
dir[i][j] = 'A';//斜上方
}
}
}
}
}
public void getLSEdits(){
int i = aL;
int j = bL;
while(i > 0 || j > 0){
if(dir[i][j] == 'A'){
aa.insert(0, A.charAt(i - 1));
bb.insert(0, B.charAt(j - 1));
i--;
j--;
}else if(dir[i][j] == 'U'){
aa.insert(0,A.charAt(i - 1));
bb.insert(0,'-');
i--;
}else{
aa.insert(0,'-');
bb.insert(0,B.charAt(j - 1));
j--;
}
}
}
public void print(){
// for(int i = 0;i <= aL;i++){
// for(int j = 0;j <= bL;j++){
// System.out.print(levAB[i][j]);
// }
// System.out.println();
// }
// System.out.println();
// for(int i = 0;i <= aL;i++){
// for(int j = 0;j <= bL;j++){
// System.out.print(dir[i][j]);
// }
// System.out.println();
// }
// System.out.println();
System.out.println("最小编辑距离是:" + levAB[aL][bL]);
System.out.println(aa);
System.out.println(bb);
System.out.println();
System.out.println("最长公共子串长度为:" + maxSubStringLen);
System.out.println("最长公共子串:" + maxSubString);
}
public void getMaxSameSubString(){
//求最长公共子串
char[] c1 = A.toCharArray();
char[] c2 = B.toCharArray();
int[][] a = new int[c1.length+1][c2.length+1];
int maxi = 0;
for(int i = 1; i < a.length; i++){
for(int j = 1; j < a[i].length; j++){
if(c1[ i - 1 ] == c2[ j - 1]) {
a[i][j] = a[i - 1][j - 1] + 1; //填空
if(a[i][j] > maxSubStringLen){
maxSubStringLen = a[i][j];
maxi = i;
}
}
}
}
maxSubString = A.substring(maxi - maxSubStringLen,maxi);
}
public static void main(String[]args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入字符串A:");
String A = sc.nextLine();
System.out.println("请输入字符串B:");
String B = sc.nextLine();
DP_Levenshtein ls = new DP_Levenshtein(A,B);
ls.getLSEditDist();
ls.getLSEdits();
ls.getMaxSameSubString();
ls.print();
}
}
2.0-1背包DP算法
import java.util.Scanner;
/**
* @author: cuttle
* @Date: 2020/10/29 15:27
* @Description: 0-1背包问题DP算法
*/
public class DP0_1Knapsack {
private int n;//n个物品
private int W;//背包容量
private int[] w;//物品重量
private int[] v;//物品价值
private int[][] V;
private int[] X;//物品的装入情况
private int MaxValue;
public DP0_1Knapsack(){
init();
V = new int[n + 1][W + 1];
X = new int[n];
}
public void init(){
Scanner sc = new Scanner(System.in);
System.out.println("请输入物品数目n:");
n = sc.nextInt();
w = new int[n];
v = new int[n];
System.out.println("请输入背包容量W:");
W = sc.nextInt();
System.out.println("请输入n个物品的重量:");
for(int i = 0;i < n;i++){
w[i] = sc.nextInt();
}
System.out.println("请输入n个物品的价值:");
for(int i = 0;i < n;i++){
v[i] = sc.nextInt();
}
}
public void dp0_1Knapsack(){
for(int i = 0;i <= n;i++){
for(int j = 0;j <= W;j++){
if(i == 0 || j == 0){
V[i][j] = 0;
}else {
if(j < w[i - 1]){
V[i][j] = V[i - 1][j];
}else{
V[i][j] = (V[i - 1][j]) > (V[i - 1][j - w[i - 1]] + v[i - 1]) ? (V[i - 1][j]) : (V[i - 1][j - w[i - 1]] + v[i - 1]);
}
}
}
}
int j = W;
for(int i = n;i > 0;i--){
if(V[i][j] == V[i - 1][j]){
X[i - 1] = 0;
}else{
X[i - 1] = 1;
j -= w[i - 1];
}
}
MaxValue = V[n][W];
}
public void print(){
System.out.println("背包可获得的最大价值为:" + MaxValue);
System.out.println("加入的物品为:");
for(int i = 0;i < n;i++){
if(X[i] == 1){
System.out.print("重量为" + w[i] + ",价值为" + v[i]);
System.out.println();
}
}
}
public static void main(String[]args){
DP0_1Knapsack dpk = new DP0_1Knapsack();
dpk.dp0_1Knapsack();
dpk.print();
}
}
3.TSP问题DP算法
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
public class DP_TSP1 {
private double[][] dArray; //距离矩阵
private int length; //距离矩阵的长度
private int lengthOfLength; //距离矩阵长度字符串的长度
private String allzero = ""; //0组成的字符串 最大值是length个(length - 1)连接起来的字符串,同样最小值是length个0连接起来
private String biggest ="";
private List<String> list = new ArrayList<String>();
private Map<String, Double> store; //存储中间数据
private String firnalCityFlow = ""; //最终形成的城市流
private String min; //最终求得的最小值
public DP_TSP1(double[][] dArray) {
this.dArray = dArray;
this.length = dArray.length;
this.lengthOfLength = (length - 1 + "").length();
for (int zeroLength = 0; zeroLength < (length * lengthOfLength);) {
allzero += 0;
zeroLength = allzero.length();
}
for(int i = this.length; i > 0; i--){
this.biggest += this.toLengthOfLength(i - 1);
}
this.allFlow();
this.initstoreMap();
this.guihua(this.length - 2);
}
public String getFirnalCityFlow() {
if ("".equals(this.firnalCityFlow)) {
return "";
}
return this.firnalCityFlow;
}
public String getMin() {
return this.min;
}
//对于一个doulbe类型的数组,只有第i个元素为0的判断
private boolean oneZero(double[] dArray, int i) {
int numOfZero = 0;
for (double d : dArray) {
if (d == 0.0) {
numOfZero++;
}
}
if (numOfZero == 1 && (dArray[i] == 0)) {
return true;
} else {
return false;
}
}
private boolean oneFlow(String str) {
//将一个字符串更改为一个字符链表
List<String> listString = new ArrayList<String>();
for (int i = 0; i < (this.length * this.lengthOfLength);) {
listString.add(str.substring(i, i + this.lengthOfLength));
i += this.lengthOfLength;
}
//如果有相同的元素,则false
for (int i = 0; i < (this.length - 1); i++) {
for (int j = i + 1; j < this.length; j++) {
if (listString.get(i * this.lengthOfLength).equals(listString.get(j * this.lengthOfLength))) {
return false;
}
}
}
//如果有距离矩阵全0对角线上的元素,则false
for (int i = 0; i < listString.size(); i++) {
if (Integer.parseInt(listString.get(i)) == i) {
return false;
}
}
//排除没有遍历所有城市的情况(从0点出发到达0点)
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < this.length;) {
map.put(i, Integer.parseInt(str.substring(i, i + this.lengthOfLength)));
i += this.lengthOfLength;
}
int allcity = 0;
for (int i = 0;;) {
i = map.get(i);
allcity++;
if (i == 0) {
break;
}
}
if (allcity < this.length) {
return false;
}
return true;
}
//初始化存储map
private void initstoreMap() {
this.store = new HashMap<String, Double>();
//存距离矩阵最后一行可能的列号
for (int i = 0; i < this.length - 1; i++) {
this.store.put(this.toLengthOfLength(i), this.dArray[this.length - 1][i]);
}
//存距离矩阵倒数两行可能的列号
for (int i = 0; i < this.length; i++) {
if(i == this.length -2)
continue;
for (int j = 0; j < this.length - 1; j++) {
if (i == j) {
continue;
}
store.put(this.toLengthOfLength(i) + this.toLengthOfLength(j), this.dArray[this.length - 2][i] + store.get(this.toLengthOfLength(j)));
}
}
}
private void guihua(int temp) {
if (list.size() == 1) {
this.thePrint(list.get(0));
this.min = this.store.get(list.get(0)) + "";
return;
}
for (int i = 0; i < (list.size() - 1); i++) {
int next = (i + 1);
if (list.get(i).substring(0, temp * this.lengthOfLength).equals(list.get(next).substring(0, temp * this.lengthOfLength))) {
double iValue = 0;
double nextValue = 0;
iValue = this.dArray[temp][Integer.parseInt(list.get(i).substring(temp, temp + this.lengthOfLength))] +
store.get(list.get(i).substring((temp + 1) * this.lengthOfLength));
nextValue = this.dArray[temp][Integer.parseInt(list.get(next).substring(temp, temp + this.lengthOfLength))] +
store.get(list.get(next).substring((temp + 1) * this.lengthOfLength));
this.store.put(list.get(i).substring(temp * this.lengthOfLength), iValue);
this.store.put(list.get(next).substring(temp * this.lengthOfLength), nextValue);
if (iValue >= nextValue) {
list.remove(i);
} else {
list.remove(next);
}
i--;
}
}
this.guihua(temp - 1);
}
//组成所有的城市流
private void allFlow() {
while (!this.biggest.equals(this.allzero)) {
this.allzero = this.addone(this.allzero);
if (this.oneFlow(this.allzero)) {
this.list.add(this.allzero);
}
}
}
//将length进制的字符串加1操作
private String addone(String str) {
List<String> listString = new ArrayList<String>();
for (int i = 0; i < (this.length * this.lengthOfLength);) {
listString.add(str.substring(i, i + this.lengthOfLength));
i += this.lengthOfLength;
}
for (int i = (length - 1); i > -1; i--) {
int last = Integer.parseInt(listString.get(i));
if (last == (length - 1)) {
last = 0;
String strLast = this.toLengthOfLength(last);
listString.set(i, strLast);
} else {
last++;
String strLast = this.toLengthOfLength(last);
listString.set(i, strLast);
break;
}
}
String ret = "";
for (String s : listString) {
ret += s;
}
return ret;
}
//如果一个int字符串长度不够lengthOfLength 则补足
private String toLengthOfLength(Object i) {
String returnString = i.toString();
while (returnString.length() < this.lengthOfLength) {
returnString = (0 + returnString);
}
return returnString;
}
//将一个字符串键值映射,并标准输出
private void thePrint(String str) {
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < this.length;) {
map.put(i, Integer.parseInt(str.substring(i, i + this.lengthOfLength)));
i += this.lengthOfLength;
}
String cityFlow = this.toLengthOfLength(0);
for (int i = 0;;) {
i = map.get(i);
cityFlow += this.toLengthOfLength(i);
if (i == 0) {
break;
}
}
for (int i = 0; i < this.length + 1;) {
if (i < (this.length)) {
this.firnalCityFlow += Integer.parseInt(cityFlow.substring(i, i + this.lengthOfLength)) + "->";
} else {
this.firnalCityFlow += Integer.parseInt(cityFlow.substring(i, i + this.lengthOfLength));
}
i += this.lengthOfLength;
}
}
public static void main(String[] args) {
double[][] first = {
{0, 2, 3, 8, 3},
{2, 0, 6, 1, 2},
{3, 6, 0, 1, 4},
{8, 1, 1, 0, 1},
{3, 2, 4, 1, 0}};
// double inf = Double.MAX_VALUE;
// double[][] first = {
// {0, 4,5, inf, 11, inf, inf, inf},
// {4, 0, inf, inf, inf, 14, inf, 12},
// {5, inf, 0, 1, inf, 12, inf, inf},
// {inf, inf, 1, 0, 6, inf, inf, 3},
// {11, inf, inf, 6, 0, inf, 9, inf},
// {inf, 14, 12, inf, inf, 0, 13, inf},
// {inf, inf, inf, inf, 9, 13, 0, 3},
// {inf, 12, inf, 3, inf, inf, 3, 0}};
DP_TSP1 ff = new DP_TSP1(first);
System.out.println("城市顺序:" + ff.getFirnalCityFlow());
System.out.println("最小值:" + ff.getMin());
}
}