4.3 最长的公共子序列
import java.util.Scanner;
public class Test4_3 {
static String s1;
static String s2;
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("输入字符串s1:");
s1=scanner.next();
System.out.println("输入字符串s2:");
s2=scanner.next();
int len1=s1.length(); //计算两个字符串的长度
int len2=s2.length();
int[][] c=new int[len1+1][len2+1]; //存放公共子序列的最大长度
int[][] b=new int[len1+1][len2+1]; //记录来源
for(int i=0;i<=len1;i++)
c[i][0]=0; //初始化第一列为0
for(int j=0;j<=len2;j++)
c[0][j]=0; //初始化第一行为0
LCSL(c,b); //求解最长公共子序列
System.out.println("s1和s2的最长公共子序列长度是:"+c[len1][len2]);
System.out.print("s1和s2的最长公共子序列是:");
print(len1,len2,b); //递归构造最长公共子序列最优解
}
/*求解最长公共子序列*/
public static void LCSL(int[][] c,int[][] b) {
int i,j;
for(i=1;i<=c.length-1;i++) { //控制s1的序列,即遍历s1的每个字符
for(j=1;j<=c[i].length-1;j++) { //控制s2的序列,即用s1的字符与s2的所有字符进行比较
if(s1.charAt(i-1)==s2.charAt(j-1)) { //字符下标从0开始
//如果当前字符相同,则公共子序列的长度为该字符前的最长公共序列+1
c[i][j]=c[i-1][j-1]+1;
b[i][j]=1;
}
else {
if(c[i][j-1]>=c[i-1][j]) { //找出两者最大值,若相等默认取左侧
c[i][j]=c[i][j-1]; //取左侧值
b[i][j]=2;
}
else {
c[i][j]=c[i-1][j]; //取上面值
b[i][j]=3;
}
}
}
}
}
/*递归构造最长公共子序列最优解*/
public static void print(int i,int j,int[][] b) {
if(i==0||j==0)
return; //递归结束条件
if(b[i][j]==1) { //来源左上角
print(i-1,j-1,b);
System.out.print(s1.charAt(i-1));
}
else if(b[i][j]==2)
print(i,j-1,b); //来源左侧
else
print(i-1,j,b); //来源上面
}
}
程序运行结果如下:
4.4 编辑距离
import java.util.Scanner;
public class Test4_4 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("输入字符串str1:");
String str1=scanner.next();
System.out.println("输入字符串str2:");
String str2=scanner.next();
int answer=editDistance(str1,str2); //求编辑距离
System.out.println(str1+"和"+str2+"的编辑距离是:"+answer);
}
public static int editDistance(String str1,String str2) {
int len1=str1.length(); //计算字符串的长度
int len2=str2.length();
int[][] d=new int[len1+1][len2+1]; //d[i][j]表示str1前i个字符和str2前j个字符的编辑距离
for(int i=0;i<=len1;i++) //当第二个字符串长度为0时,编辑距离初始化为i
d[i][0]=i;
for(int j=0;j<=len2;j++) //当第一个字符串长度为0时,编辑距离初始化为j
d[0][j]=j;
for(int i=1;i<d.length;i++) { //遍历str1的每个字符
for(int j=1;j<d[i].length;j++) { //与第二个字符串的每个字符进行比较
int diff; //判断str1[i]是否等于str2[j],相等为0
if(str1.charAt(i-1)==str2.charAt(j-1)) { //字符串小标从0开始
diff=0;
}
else
diff=1;
int temp=Math.min(d[i-1][j]+1, d[i][j-1]+1); //去三者中最小值
d[i][j]=Math.min(temp,d[i-1][j-1]+diff);
}
}
return d[len1][len2];
}
}
程序运行结果如下:
4.5 游艇租赁
import java.util.Scanner;
public class Test4_5 {
static int n;
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("请输入站点的个数n:");
n=scanner.nextInt();
System.out.println("请依次输入各站点之间的租金:");
int[][] r=new int[n+1][n+1]; //存放各站点之间的租金
int[][] m=new int[n+1][n+1]; //各个子问题的最优值
int[][] s=new int[n+1][n+1]; //各个子问题的最优决策
for(int i=1;i<=n;i++) {
for(int j=i+1;j<=n;j++) {
r[i][j]=scanner.nextInt();
m[i][j]=r[i][j]; //初始化m数组
}
}
rent(m,s); //求最少租金
System.out.println("花费最少的租金为:"+m[1][n]);
System.out.print("最少租金经过的站点:1");
print(1,n,s);
System.out.println();
scanner.close();
}
/*最少租金求解函数*/
public static void rent(int[][] m,int[][] s) {
int i,j,k,d;
for(d=3;d<=n;d++) { //将问题划分为小规模d,3个站点、4个站点...n个站点
for(i=1;i<=n-d+1;i++) { //子问题的初始站点
j=i+d-1; //子问题的终点站点
for(k=i+1;k<j;k++) { //可停靠站点
int temp=m[i][k]+m[k][j]; //在站点k停留
if(temp<m[i][j]) { //停留后的租金和比直达的租金便宜
m[i][j]=temp;
s[i][j]=k; //记录停靠点
}
}
}
}
}
/*求得停靠点,当s[i][j]=0时说明中间没有停靠点,输出站点j,否则划分为两个子问题*/
public static void print(int i,int j,int[][] s) {
if(s[i][j]==0) {
System.out.print("——"+j);
return;
}
print(i,s[i][j],s);
print(s[i][j],j,s);
}
}
程序运行结果如下:
4.6 矩阵连乘
import java.util.Scanner;
public class Test4_6 {
static int n;
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("请输入矩阵的个数n:");
n=scanner.nextInt();
int[] p=new int[n+1]; //记录矩阵行列
int[][] m=new int[n+1][n+1]; //最优值数组
int[][] s=new int[n+1][n+1]; //最优决策数组
System.out.println("请依次输入每个矩阵的行数和最后一个矩阵的列数:");
for(int i=0;i<=n;i++)
p[i]=scanner.nextInt();
matrixChain(p,m,s); //矩阵连乘求解函数
print(1,n,s);
System.out.println();
System.out.println("最小计算量的值为:"+m[1][n]);
}
/*矩阵连乘求解函数*/
public static void matrixChain(int[] p,int[][] m,int[][] s) {
int i,j,r,k;
for(r=2;r<=n;r++) { //2个矩阵连乘、3个矩阵连乘...n个矩阵连乘
for(i=1;i<=n-r+1;i++) { //r个矩阵开始矩阵的下标
j=i+r-1; //结束矩阵
m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j]; //k=i时的乘法次数
s[i][j]=i; //子问题的最优策略是i
for(k=i+1;k<j;k++) { //对从i到j的所有策略求最优值
int temp=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
if(temp<m[i][j]) {
m[i][j]=temp;
s[i][j]=k;
}
}
}
}
}
/*最优解输出函数*/
public static void print(int i,int j,int[][] s) {
if(i==j) {
System.out.print("A"+i);
return;
}
System.out.print("(");
print(i,s[i][j],s);
print(s[i][j]+1,j,s);
System.out.print(")");
}
}
程序运行结果如下:
4.9 0-1背包问题
import java.util.Scanner;
public class Test4_9 {
public static void main(String[] args) {
int n,W; //n表示n个物品,W表示购物车容量
Scanner scanner=new Scanner(System.in);
System.out.println("请输入物品的个数n:");
n=scanner.nextInt();
System.out.println("请输入购物车的容量W:");
W=scanner.nextInt();
int[] w=new int[n+1]; //存放所有物品的重量
int[] v=new int[n+1]; //存放所有物品的价值
int[][] c=new int[n+1][W+1]; //表示前i个物品放入容量为j的购物车获得的最大价值
System.out.println("请依次输入每个物品的重量w和价值v,用空格分开:");
for(int i=1;i<=n;i++) {
w[i]=scanner.nextInt();
v[i]=scanner.nextInt();
}
//计算c[i][j]
for(int i=1;i<=n;i++) { //控制物品个数
for(int j=1;j<=W;j++) { //控制容量大小
if(w[i]>j) //物品重量大于购物车容量,则不放入第i个物品
c[i][j]=c[i-1][j];
else
c[i][j]=Math.max(c[i-1][j],c[i-1][j-w[i]]+v[i]);//比较放入此物品与不放入此物品哪个价值更大
}
}
System.out.println("装入购物车的最大价值为:"+c[n][W]);
//逆向构造最优解
int[] x=new int[n+1]; //表示第i个物品是否放入购物车
int j=W;
for(int i=n;i>0;i--) { //从最后一个物品开始判断
if(c[i][j]>c[i-1][j]) { //说明第i个物品放入购物车
x[i]=1;
j-=w[i];
}
else
x[i]=0; //说明第i个物品没有放入购物车
}
System.out.println("装入购物车的物品为:");
for(int i=1;i<=n;i++) {
if(x[i]==1)
System.out.print(i+" ");
}
}
}
程序运行结果如下: