2.15

CF607B Zuma - 洛谷 (luogu.com.cn)

  • \(dp[i][j]\)表示在这个\((i,j)\)区间中所使用的最短时间。
  • 考虑转移方程,因为是回文字符串,所以当\(arr[left] != arr[right]\)时,有\(dp[left][right] = dp[left + 1][right - 1]\),因为用同一步可以同时消除他们,当\(arr[left] == arr[right]\)时,有\(dp[left][right]=min(dp[left][k] + dp[k+1][right])\)
  • 考虑递归顺序,由于我们是用小区间推导大区间,所以是从小到大
  • 考虑初始状态,先考虑长度为1和2时,则需要初始化一下长度为1,2的区间,\(dp[i][i]=1,dp[i][i+1]=(1,2)\),于是就可以直接做了
import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;

public class Main implements Runnable {

    static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
    static int n;
    static final int N = (int) (5e2 + 10);
    static int[] arr = new int[N];
    static int[][] dp = new int[N][N];

    public static void main(String[] args) {
        new Thread(null, new Main(), "", 1 << 29).start();
    }

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int) cin.nval;
    }

    public static String next() throws IOException {
        cin.nextToken();
        return cin.sval;
    }




    @Override
    public void run() {
        try {
            n = nextInt();
            for (int i = 1; i <=n; i++) {
                Arrays.fill(dp[i], 0x3f3f3f3f);
            }
            for (int i = 1; i <= n; i++) {
                arr[i] = nextInt();
                dp[i][i] = 1;
            }

            for (int left = 1; left + 1 <= n; left++) {
                int right = left + 1;
                if (arr[left] != arr[right]) {
                    dp[left][right] = 2;
                } else {
                    dp[left][right] = 1;
                }
            }
            for (int len = 3; len <= n; len++) {
                for (int left = 1; left + len - 1 <= n; left++) {
                    int right = left + len - 1;
                    if (arr[left] == arr[right]) {
                        dp[left][right] = dp[left + 1][right - 1];
                    }
                    for (int k = left; k < right; k++) {
                        dp[left][right] = Math.min(dp[left][right], dp[left][k] + dp[k + 1][right]);
                    }
                }
            }
            cout.println(dp[1][n]);
            cout.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}

[P4170 CQOI2007] 涂色 - 洛谷 (luogu.com.cn)

  • \(dp[i][j]\)表示区间(i,j)的最少涂色次数
  • 转移方程其实和上题有一点相似
import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;

public class Main implements Runnable {

    static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
    static final int N = 55;
    static int[] arr = new int[N];
    static int[][] dp = new int[N][N];//dp[i,j]表示i,j的最少涂色次数
    //dp[i,i] 1次 dp[i,i+1] 2次

    public static void main(String[] args) {
        new Thread(null, new Main(), "", 1 << 29).start();
    }

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int) cin.nval;
    }

    public static String next() throws IOException {
        cin.nextToken();
        return cin.sval;
    }




    @Override
    public void run() {
        try {
            String s = next();
            for (int i = 1; i <= s.length(); i++) {
                Arrays.fill(dp[i], 0x3f3f3f3f);
            }
            for (int i = 1; i <= s.length(); i++) {
                arr[i] = s.charAt(i - 1) - 'A';
                dp[i][i] = 1;
            }

            for (int i = 1; i < s.length(); i++) {
                if (arr[i] != arr[i + 1]) {
                    dp[i][i + 1] = 2;
                } else {
                    dp[i][i + 1] = 1;
                }
            }

            for (int len = 3; len <= s.length(); len++) {
                for (int left = 1; left + len - 1 <= s.length(); left++) {
                    int right = left + len - 1;
                    if (arr[left] == arr[right]) {
                        dp[left][right] = Math.min(dp[left][right - 1], dp[left + 1][right]);
                    }
                    for (int k = left; k < right; k++) {
                        dp[left][right] = Math.min(dp[left][right], dp[left][k] + dp[k + 1][right]);
                    }
                }
            }

            cout.println(dp[1][s.length()]);
            cout.flush();

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}

[P4290 HAOI2008] 玩具取名 - 洛谷 (luogu.com.cn)

  • \(can[i][j][k]\)表示i是否可以用j和k两个字母(用数字替代)来替代,\(dp[i][j][k]\)表示k是否可以由(i, j)区间转移得到,简单说就是i,j区间转移为k这个字母
  • 转移方程由当\(dp[left][k][x] = true,dp[k+1][right][y]=true,can[z][x][y] = true\)时,\(dp[left][right][z] = true\),所以就时要遍历x,y,z,k,left,right,len即可
  • 考虑迭代方向,肯定是由小到大
  • 那么考虑初始化,就是\(dp[i][i][change(i)]\)可以想到就是i这个字母可以转移为他自身,can的初始化就不用详细说明了
  • 照着思路把代码写出来就行了
import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;

public class Main implements Runnable {

    static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
    static final int N = 215;
    static boolean[][][] can = new boolean[N][N][N];
    static boolean[][][] dp = new boolean[N][N][N];


    public static int change(char x) {
        if (x == 'W') return 1;
        if (x == 'I') return 2;
        if (x == 'N') return 3;
        return 4;
    }

    public static void main(String[] args) {
        new Thread(null, new Main(), "", 1 << 29).start();
    }

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int) cin.nval;
    }

    public static String next() throws IOException {
        cin.nextToken();
        return cin.sval;
    }


    public static void init(int x, int cnt) throws IOException {
        for (int i = 1; i <= x; i++) {
            String s = next();
            can[cnt][change(s.charAt(0))][change(s.charAt(1))] = true;
        }
    }

    @Override
    public void run() {
        try {
            int x1 = nextInt();int y1 = nextInt();int z1 = nextInt();int g = nextInt();
            init(x1, 1);init(y1,2);init(z1, 3);init(g, 4);
            String s = next();
            for (int i = 1; i <= s.length(); i++) {
                dp[i][i][change(s.charAt(i - 1))] = true;
            }
            for (int len = 2; len <= s.length(); len++) {
                for (int left = 1; left + len - 1 <= s.length(); left++) {
                    int right = left + len - 1;
                    for (int k = left; k < right; k++) {
                        for (int x = 1; x <= 4; x++) {
                            for (int y = 1; y <= 4; y++) {
                                for (int z = 1; z <= 4; z++) {
                                    if (dp[left][k][x] && dp[k + 1][right][y] && can[z][x][y]) {
                                        dp[left][right][z] = true;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            boolean flag = false;
            if (dp[1][s.length()][1]) {
                flag = true;
                cout.print('W');
            }
            if (dp[1][s.length()][2]){
                flag = true;
                cout.print('I');
            }
            if (dp[1][s.length()][3]) {
                flag = true;
                cout.print('N');
            }
            if (dp[1][s.length()][4]) {
                flag = true;
                cout.print('G');
            }
            if (!flag) {
                cout.println("The name is wrong!");
            }
            cout.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}
posted @ 2025-02-15 18:55  Mikkeykarl  阅读(12)  评论(0)    收藏  举报