动态规划算法:Levenshtein编辑距离、0-1背包、TSP问题(Java实现)

因为这学期上算法课,因为要准备蓝桥杯国赛,所以复习记录一下几个经典的算法 (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());
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值