0
点赞
收藏
分享

微信扫一扫

【Java】递推专题训练

飞鸟不急 2022-02-09 阅读 63

文章目录

题目链接

知识汇总

题目列表


快输模板

import java.io.*;
import java.util.*;
import java.util.regex.*;
public class Main {
    static class FastReader {
        BufferedReader br;
        StringTokenizer st;

        public FastReader() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }

        String nextLine() {
            String str = "";
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }

        boolean hasNext() {
            if (st != null && st.hasMoreTokens())
                return true;
            try {
                st = new StringTokenizer(br.readLine());
            } catch (Exception e) {
                return false;
            }
            return true;
        }
    }

    static PrintWriter out = new PrintWriter(
            new BufferedWriter(new OutputStreamWriter(System.out)));
    /*
    核心代码区
    */
}

A - 上台阶2

	static long dp[];
    static int mod=100003;
    public static void main(String[] args) {
        FastReader sc = new FastReader();
        int n=sc.nextInt();
        dp=new long[n+1];
        for(int i=1;i<=n;i++){
            if(i<=2)dp[i]=1;
            else if(i==3)dp[i]=dp[i-1]+1;
            else if(i==4)dp[i]=dp[i-1]+dp[i-3];
            else if(i==5)dp[i]=dp[i-1]+dp[i-3]+1;
            else dp[i]=(dp[i-1]+dp[i-3]+dp[i-5])%mod;
        }
        out.println(dp[n]);
        out.flush();
    }

B - 数字三角形

	static int map[][];
    static int n;
    public static void main(String[] args) {
        FastReader sc = new FastReader();
        n=sc.nextInt();
        map=new int[n+1][n+1];
        for(int i=1;i<=n;i++)
            for(int j=1;j<=i;j++)
                map[i][j]=sc.nextInt();
        dp();
        out.println(getMax());
        out.flush();
    }
    public static void dp(){
        for(int i=2;i<=n;i++)
            for(int j=1;j<=i;j++)
                map[i][j]=Math.max(map[i-1][j-1],map[i-1][j])+map[i][j];
    }
    public static int getMax(){
        int max=map[n][1];
        for(int i=2;i<=n;i++)
            if(map[n][i]>max) max=map[n][i];
        return max;
    }

C - 矩阵取数问题

	static int map[][];
    static int n;
    public static void main(String[] args) {
        FastReader sc = new FastReader();
        n=sc.nextInt();
        map=new int[n+1][n+1];
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                map[i][j]=sc.nextInt();
        dp();
        out.println(getMax());
        out.flush();
    }
    public static void dp(){
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                map[i][j]=Math.max(map[i-1][j],map[i][j-1])+map[i][j];
    }
    public static int getMax(){
        int max=map[n][1];
        for(int i=2;i<=n;i++)
            if(map[n][i]>max) max=map[n][i];
        return max;
    }

D - 背包问题(01背包)

	static int dp[],w[],p[];//w[]容积数组,p[]价值数组
    static int n,w0;//数量,容量
    public static void main(String[] args) {
        FastReader sc = new FastReader();
        n=sc.nextInt();
        w0=sc.nextInt();
        //dp数组:放入容量为v的背包中的最大价值
        dp=new int[w0+1];
        w=new int[n+1];
        p=new int[n+1];
        for(int i=1;i<=n;i++){
            w[i]=sc.nextInt();
            p[i]=sc.nextInt();
        }
        for(int i=1;i<=n;i++){
            for(int v=w0;v>0;v--){
                if(v>=w[i])
                    dp[v]=Math.max(dp[v],dp[v-w[i]]+p[i]);
            }
        }
        out.println(dp[w0]);
        out.flush();
    }

E - 完全背包

	static int dp[],w[],p[];//w[]容积数组,p[]价值数组
    static int n,w0;//数量,容量
    public static void main(String[] args) {
        FastReader sc = new FastReader();
        n=sc.nextInt();
        w0=sc.nextInt();
        //dp数组:放入容量为v的背包中的最大价值
        dp=new int[w0+1];
        w=new int[n+1];
        p=new int[n+1];
        for(int i=1;i<=n;i++){
            w[i]=sc.nextInt();
            p[i]=sc.nextInt();
        }
        for(int i=1;i<=n;i++){
            for(int v=w[i];v<=w0;v++){
                if(v>=w[i])
                    dp[v]=Math.max(dp[v],dp[v-w[i]]+p[i]);
            }
        }
        out.println(dp[w0]);
        out.flush();
    }

F - 背包问题 V2

	static int dp[],w[],p[];//w[]容积数组,p[]价值数组
    static int n,w0,n1;//数量,容量,计数器
    public static void main(String[] args) {
        FastReader sc = new FastReader();
        n=sc.nextInt();
        w0=sc.nextInt();
        //dp数组:放入容量为v的背包中的最大价值
        dp=new int[w0+1];
        w=new int[2000010];
        p=new int[2000010];
        for(int i=1;i<=n;i++){
            int ww=sc.nextInt();//体积
            int pp=sc.nextInt();//价值
            int c=sc.nextInt();//第i件物品数量
            int t=1;
            while (c>=t) {
                w[++n1]=ww*t;//相当于n1++;  w[n1]=w[i]*t;
                p[n1]=pp*t;
                c-=t;
                t*=2;
            }
            w[++n1]=ww*c;
            p[n1]=pp*c;
        }
        for(int i=1;i<=n1;i++){
            for(int v=w0;v>=w[i]/*终止条件更改到for语句中*/;v--){
                dp[v]=Math.max(dp[v],dp[v-w[i]]+p[i]);
            }
        }
        out.println(dp[w0]);
        out.flush();
    }

G - 最长上升子序列

	//dp[n]:代表以第n个元素结尾的LIS序列的长度
    static int dp[],a[];
    static int n;
    public static void main(String[] args) {
        FastReader sc = new FastReader();
        n=sc.nextInt();
        dp=new int[n];
        a=new int[n];
        for(int i=0;i<n;i++) a[i]=sc.nextInt();
        dp[0]=1;
        for(int i=1;i<n;i++) {
            int t=0;
            for(int j=0;j<i;j++) {
                if(a[j]<a[i]) {
                    if(t<dp[j])t=dp[j];
                }
            }
            dp[i]=t+1;
        }
        int t=0;
        for(int i=0;i<n;i++) {
            if(t<dp[i])t=dp[i];
        }
        out.println(t);
        out.flush();
    }

H - 最长公共子序列

	/*
	状态转移方程如下:
 	x[i]=y[i]:   dp[i][j]=dp[i-1][j-1]+1
	x[i]!=y[j]:  dp[i][j]=max(dp[i-1][j],dp[i][j-1])
	i=0||j=0:    dp[i][j]=0
	*/
	static char c1[],c2[];
    static int n,m;
    static int dp[][];
    public static void main(String[] args) {
        FastReader sc = new FastReader();
        c1=(" "+sc.next()).toCharArray();
        c2=(" "+sc.next()).toCharArray();
        n=c1.length-1;m=c2.length-1;
        //dp[i][j]:字符串1的前i位和字符串2的前j位的LCS长度
        dp=new int[n+1][m+1];
        for(int i=1;i<=n;i++) {
            for(int j=1;j<=m;j++) {
                if(c1[i]==c2[j]) {
                    dp[i][j]=dp[i-1][j-1]+1;
                }
                else {
                    dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
                }
            }
        }
        dfs(n,m);
        out.println();
        out.flush();
    }
    public static int dfs(int i,int j) {
        //字符串第一位均是空位,不算
        if(i==0||j==0) return 0;
        if(c1[i]==c2[j]){
            dfs(i-1,j-1);
            out.print(c1[i]);
        }
        else{
            if(dp[i-1][j]>dp[i][j-1])dfs(i-1,j);
            else dfs(i,j-1);
        }
        return 0;
    }

I - 石子合并(环形合并)

	static int n,minl,maxl;//n堆石子
    //f[i][j]:表示从i到j堆石子合并后的最大f1/最小得分f2
    static int num[],s[],f1[][],f2[][];
    //转移方程:f[i][j] = max(f[i][k]+f[k+1][j]+d[i][j];
    //d(i,j)表示从i到j石子个数的和
    public static void main(String[] args) {
        FastReader sc = new FastReader();
        n=sc.nextInt();
        int N=2*n+1;
        //因为是一个环,所以需要开到两倍再枚举分界线,最后肯定是最大的
        num=new int[N];
        s=new int[N];
        f1=new int[N][N];//max
        f2=new int[N][N];//min
        for(int i=1;i<=n+n;i++){
            if(i<=n){
                num[i]=sc.nextInt();
                num[i+n]=num[i];
            }
            s[i]=s[i-1]+num[i];
        }
        for(int p=1;p<n;p++) {
            for(int i=1,j=i+p;(j<n+n) && (i<n+n);i++,j=i+p) {
                f2[i][j]=999999999;
                for(int k=i;k<j;k++)
                {
                    f1[i][j] = Math.max(f1[i][j], f1[i][k]+f1[k+1][j]+d(i,j));
                    f2[i][j] = Math.min(f2[i][j], f2[i][k]+f2[k+1][j]+d(i,j));
                }
            }
        }
        minl=999999999;
        for(int i=1;i<=n;i++)
        {
            maxl=Math.max(maxl,f1[i][i+n-1]);
            minl=Math.min(minl,f2[i][i+n-1]);
        }
        out.printf("%d\n%d",minl,maxl);
        out.flush();
    }
    public static int d(int i,int j){return s[j]-s[i-1];}

J - 循环数组最大子段和

	public static void main(String[] args) {
        FastReader sc = new FastReader();
        int n=sc.nextInt();
        long sum=0;
        int num[]=new int[n+1];
        for(int i=0;i<n;i++){
            num[i]=sc.nextInt();
            sum+=num[i];
        }
        //样例超出int范围
        long dp[]=new long[n];
        for(int i=0;i<n;i++)//找最大子段
            if(i>0&&dp[i-1]>0)
                dp[i]=dp[i-1]+num[i];
            else
                dp[i]=num[i];
        long min=(int)1e9+7,max=0;
        for(int i=0;i<n;i++)
            if(max<dp[i])
                max=dp[i];
        for(int i=0;i<n;i++)//找最小子段
            if(i>0&&dp[i-1]<0)
                dp[i]=dp[i-1]+num[i];
            else
                dp[i]=num[i];
        for(int i=0;i<n;i++)
            if(min>dp[i])
                min=dp[i];
        min=sum-min;
        out.println(Math.max(min,max));
        out.flush();
    }

K - 没有上司的舞会

查了一下,大概是这样的操作不安全,可能使程序崩溃。
改成用结点类封装list,再进行操作就编译通过了。
ps:如果用二维数组代替list的功能可能会MLE(甚至出现了RE :- ()

	//主程序
	static node tree[];
    static int ri[],vis[],f[][];//ri[]快乐指数
    static int n;//总人数
    //f[i][0]:i不来的情况下以i为根节点的子树的最大快乐值
    //f[i][1]:i来的情况下以i为根节点的子树的最大快乐值
    public static void main(String[] args) {
        FastReader sc = new FastReader();
        n=sc.nextInt();
        ri=new int[n+1];
        vis=new int[n+1];
        tree=new node[n+1];
        f=new int[n+1][2];
        for(int i=1;i<=n;i++)ri[i]=sc.nextInt();
        for(int i=1;i<n;i++){
            int x=sc.nextInt();
            int y=sc.nextInt();
            if(tree[x]==null)tree[x]=new node();
            if(tree[y]==null)tree[y]=new node();
            tree[x].ad(y);
            tree[y].ad(x);
        }
        dfs(1);//从根节点找子树
        out.println(Math.max(f[1][0],f[1][1]));
        out.flush();
    }
    public static void dfs(int x){
        vis[x]=1;
        f[x][0]=0;
        f[x][1]=ri[x];
        for(int i=0;i<tree[x].length;i++){
            int son=tree[x].gt(i);
            if(vis[son]!=0)continue;
            dfs(son);
            f[x][0]+=Math.max(f[son][0],f[son][1]);
            f[x][1]+=f[son][0];
        }
    }
//结点类
class node{
    int length;
    List<Integer> ls;
    public node() {
        ls=new ArrayList<>();
        length=0;
    }
    public void ad(int x){
        ls.add(x);
        length++;
    }
    public int gt(int x){
        return ls.get(x);
    }
}

L - 滑雪

	static int n,m;//row & column
    static int dp[][]=new int[110][110];
    static int mp[][]=new int[110][110];//地图(高度)
    static int dir[][]={{1,0},{-1,0},{0,-1},{0,1}};//搜索方向
    public static void main(String[] args) {
        FastReader sc = new FastReader();
        int i,j;
        n=sc.nextInt();
        m=sc.nextInt();
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
                mp[i][j]=sc.nextInt();
        int s=0;
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
                s=Math.max(find(i,j), s);
        out.printf("%d\n",s);
        out.flush();
    }
    public static int find(int x,int y) //找出从该点开始能进行的最大次数
    {
        if(dp[x][y]!=0)
            return dp[x][y];
        int d=1,tx,ty;
        for(int k=0;k<4;k++)
        {
            tx=x+dir[k][0];
            ty=y+dir[k][1];
            if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&mp[x][y]>mp[tx][ty])
                d=Math.max(find(tx,ty)+1,d);
        }
        dp[x][y]=d;
        return d;
    }
举报

相关推荐

0 条评论