HNUCMOJ题解

HNUCMOJ

2022年春季学期《算法分析与设计》练习8

前6题为必做题,最后2题为选做题!
写在前面:
题目还是没那么难的,只是有些东西不好理解,可以像老师一样画图帮助理解

1、 问题 A: 数字三角形之动态规划法

AC代码:

import java.util.Arrays;
import java.util.Scanner;
 
public class Main {
 
    public static int n;
    public static int[][]arr,Maxsum;
 
 
    public static int solve(int i,int j){
        if(Maxsum[i][j]>=0)return Maxsum[i][j];
        if(i==n)return arr[i][j];
        else {
            Maxsum[i][j]=Math.max(solve(i+1,j),solve(i+1,j+1))+arr[i][j];
        }
        return Maxsum[i][j];
    }
 
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        while(sc.hasNext()){
            n=sc.nextInt();
            arr=new int[110][110];
            Maxsum=new int[110][110];
//            Arrays.fill(Maxsum,-1);只适用一维数组
            for(int i=1;i<=n;i++){
                for(int j=1;j<=i;j++){
                    arr[i][j]=sc.nextInt();
                    Maxsum[i][j]=-1;
                }
            }
 
            System.out.println(solve(1,1));
        }
    }
}

这里面的dp数组的初始化用了循环,如果是对于一维数组的初始化可以使用Arrays.fill()函数

2、问题 B: 滚球游戏

AC代码:

import java.util.Scanner;
 
public class Main {
 
    public static int n;
    public static int[][]arr,Maxsum;
 
    public static void solve(){
        for(int j=1;j<=2*n-1;j++){
            Maxsum[n][j]=arr[n][j];
        }
        for(int i=n-1;i>=1;i--){
            for(int j=1;j<=2*i-1;j++){
                int max = Math.max(Maxsum[i + 1][j], Maxsum[i + 1][j + 1]);
                max = Math.max(max, Maxsum[i + 1][j+2]);
//                System.out.println("**"+max+"**"+Maxsum[i + 1][j+2]);
                Maxsum[i][j]=max+arr[i][j];
            }
        }
    }
 
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int flag=0;
        while(sc.hasNext()){
            if(flag==0){
                n=sc.nextInt();
                arr=new int[550][550];
                Maxsum=new int[550][550];
                flag=1;
            }else{
                sc.nextLine();
                n=sc.nextInt();
                arr=new int[550][550];
                Maxsum=new int[550][550];
            }
 
//            Arrays.fill(Maxsum,-1);只适用一维数组
            for(int i=1;i<=n;i++){
                for(int j=1;j<=2*i-1;j++){
                    arr[i][j]=sc.nextInt();
                    Maxsum[i][j]=-1;
                }
            }
            solve();
            System.out.println(Maxsum[1][1]);
        }
    }
}

这里需要注意的是数组的大小,开大一点,110*110的是不够的,会有运行错误

3、最长公共子序列问题(LCS)之备忘录法

AC代码:

import java.util.Scanner;
 
public class Main {
 
    public static int[][]c=new int[550][550];;
    public static int solve(char[]str1,char[]str2,int i,int j){
        if(c[i+1][j+1]==-1){
            if(i==0||j==0)c[i][j]=0;
            else if(str1[i-1]==str2[j-1]){
                c[i][j]=solve(str1,str2,i-1,j-1)+1;
            }else{
                c[i][j]=Math.max(solve(str1,str2,i,j-1),solve(str1,str2,i-1,j));
            }
        }
        return c[i][j];
    }
 
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        char[]str1=sc.nextLine().toCharArray();
        char[]str2=sc.nextLine().toCharArray();
 
        int n=Math.min(str1.length,str2.length);
        int m=Math.max(str1.length,str2.length);
        for(int i=0;i<550;i++){
            for(int j=0;j<550;j++){
                c[i][j]=-1;
            }
        }
        System.out.println(solve(str1,str2,str1.length,str2.length));
    }
}
 
4、问题 D: 最长公共子序列问题(LCS)之动态规划法

AC代码:

import java.util.Scanner;
 
public class Main {
 
    public static int[][]c=new int[550][550];//初始值就是0
    public static void solve(char[]str1,char[]str2,int i,int j){
 
        for(int k=1;k<=i;k++){
            for(int m=1;m<=j;m++){
                if(str1[k-1]==str2[m-1])c[k][m]=c[k-1][m-1]+1;
                else if(c[k][m-1]>=c[k-1][m])c[k][m]=c[k][m-1];
                else c[k][m]=c[k-1][m];
            }
        }
 
    }
 
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        char[]str1=sc.nextLine().toCharArray();
        char[]str2=sc.nextLine().toCharArray();
 
        solve(str1,str2,str1.length,str2.length);
        System.out.println(c[str1.length][str2.length]);
    }
}
5、问题 E: 最长公共子序列问题(LCS)-构造LCS

AC代码:

import java.util.Scanner;
 
public class Main {
    public static int[][]c=new int[550][550];//初始值就是0
    public static int[][]b=new int[550][550];
    public static void solve(char[]str1,char[]str2,int i,int j){
 
        for(int k=1;k<=i;k++){
            for(int m=1;m<=j;m++){
                if(str1[k-1]==str2[m-1]){
                    c[k][m]=c[k-1][m-1]+1;
                    b[k][m]=1;
                }
                else if(c[k][m-1]>=c[k-1][m]){
                    c[k][m]=c[k][m-1];
                    b[k][m]=3;
                }
                else {
                    c[k][m]=c[k-1][m];
                    b[k][m]=2;
                }
            }
        }
 
    }
 
    public static void solve2(int i,int j,char[]x,int[][]b){
        if(i==0||j==0)return;
        if(b[i][j]==1){
            solve2(i-1,j-1,x,b);
            System.out.print(x[i-1]);
        }else if(b[i][j]==2){
            solve2(i-1,j,x,b);
        }else if(b[i][j]==3){
            solve2(i,j-1,x,b);
        }
    }
 
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        char[]str1=sc.nextLine().toCharArray();
        char[]str2=sc.nextLine().toCharArray();
        solve(str1,str2,str1.length,str2.length);
        solve2(str1.length,str2.length,str1,b);
    }
}
6、问题 F: 牛牛的字符串

AC代码:

import java.util.Scanner;
 
public class Main {
    public static int solve(char[]str1,char[]str2){
        if (str1 == null || str2 == null) {
            return 0;
        }
        int result = 0;
        int sLength = str1.length;
        int tLength =str2.length;
        int[][] dp = new int[sLength][tLength];
        for (int i = 0; i < sLength; i++) {
            for (int k = 0; k < tLength; k++) {
                if (str1[i]==str2[k]) {
                    if (i == 0 || k == 0) {
                        dp[i][k] = 1;
                    } else {
                        dp[i][k] = dp[i - 1][k - 1] + 1;
                    }
                    result = Math.max(dp[i][k], result);
                } else {
                    dp[i][k] = 0;
                }
            }
        }
        return result;
    }
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        char[]str1=sc.nextLine().toCharArray();
        char[]str2=sc.nextLine().toCharArray();
         
        System.out.println(solve(str1,str2));
 
    }
}

学到动态规划突然发现自己好差劲啊,脑子不聪明只好多花时间了

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
06-01
这道题是一道典型的费用限制最短路题目,可以使用 Dijkstra 算法或者 SPFA 算法来解决。 具体思路如下: 1. 首先,我们需要读入输入数据。输入数据中包含了道路的数量、起点和终点,以及每条道路的起点、终点、长度和限制费用。 2. 接着,我们需要使用邻接表或邻接矩阵来存储图的信息。对于每条道路,我们可以将其起点和终点作为一个有向边的起点和终点,长度作为边权,限制费用作为边权的上界。 3. 然后,我们可以使用 Dijkstra 算法或 SPFA 算法求解从起点到终点的最短路径。在这个过程中,我们需要记录到每个点的最小费用和最小长度,以及更新每条边的最小费用和最小长度。 4. 最后,我们输出从起点到终点的最短路径长度即可。 需要注意的是,在使用 Dijkstra 算法或 SPFA 算法时,需要对每个点的最小费用和最小长度进行松弛操作。具体来说,当我们从一个点 u 经过一条边 (u,v) 到达另一个点 v 时,如果新的费用和长度比原来的小,则需要更新到达 v 的最小费用和最小长度,并将 v 加入到优先队列(Dijkstra 算法)或队列(SPFA 算法)中。 此外,还需要注意处理边权为 0 或负数的情况,以及处理无法到达终点的情况。 代码实现可以参考以下样例代码: ```c++ #include <cstdio> #include <cstring> #include <queue> #include <vector> using namespace std; const int MAXN = 1005, MAXM = 20005, INF = 0x3f3f3f3f; int n, m, s, t, cnt; int head[MAXN], dis[MAXN], vis[MAXN]; struct Edge { int v, w, c, nxt; } e[MAXM]; void addEdge(int u, int v, int w, int c) { e[++cnt].v = v, e[cnt].w = w, e[cnt].c = c, e[cnt].nxt = head[u], head[u] = cnt; } void dijkstra() { priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q; memset(dis, 0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)); dis[s] = 0; q.push(make_pair(0, s)); while (!q.empty()) { int u = q.top().second; q.pop(); if (vis[u]) continue; vis[u] = 1; for (int i = head[u]; i != -1; i = e[i].nxt) { int v = e[i].v, w = e[i].w, c = e[i].c; if (dis[u] + w < dis[v] && c >= dis[u] + w) { dis[v] = dis[u] + w; q.push(make_pair(dis[v], v)); } } } } int main() { memset(head, -1, sizeof(head)); scanf("%d %d %d %d", &n, &m, &s, &t); for (int i = 1; i <= m; i++) { int u, v, w, c; scanf("%d %d %d %d", &u, &v, &w, &c); addEdge(u, v, w, c); addEdge(v, u, w, c); } dijkstra(); if (dis[t] == INF) printf("-1\n"); else printf("%d\n", dis[t]); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是君倩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值