package class35; import java.util.Arrays; // 来自小红书 // 一场电影开始和结束时间可以用一个小数组来表示["07:30","12:00"] // 已知有2000场电影开始和结束都在同一天,这一天从00:00开始到23:59结束 // 一定要选3场完全不冲突的电影来观看,返回最大的观影时间 // 如果无法选出3场完全不冲突的电影来观看,返回-1 public class Code03_WatchMovieMaxTime { // 暴力方法,枚举前三场所有的可能全排列 public static int maxEnjoy1(int[][] movies) { if (movies.length < 3) { return -1; } return process1(movies, 0); } public static int process1(int[][] movies, int index) { if (index == 3) { int start = 0; int watch = 0; for (int i = 0; i < 3; i++) { if (start > movies[i][0]) { return -1; } watch += movies[i][1] - movies[i][0]; start = movies[i][1]; } return watch; } else { int ans = -1; for (int i = index; i < movies.length; i++) { swap(movies, index, i); ans = Math.max(ans, process1(movies, index + 1)); swap(movies, index, i); } return ans; } } public static void swap(int[][] movies, int i, int j) { int[] tmp = movies[i]; movies[i] = movies[j]; movies[j] = tmp; } // 优化后的递归解 public static int maxEnjoy2(int[][] movies) { Arrays.sort(movies, (a, b) -> a[0] != b[0] ? (a[0] - b[0]) : (a[1] - b[1])); return process2(movies, 0, 0, 3); } public static int process2(int[][] movies, int index, int time, int rest) { if (index == movies.length) { return rest == 0 ? 0 : -1; } int p1 = process2(movies, index + 1, time, rest); int next = movies[index][0] >= time && rest > 0 ? process2(movies, index + 1, movies[index][1], rest - 1) : -1; int p2 = next != -1 ? (movies[index][1] - movies[index][0] + next) : -1; return Math.max(p1, p2); } // 记忆化搜索的动态规划 public static int maxEnjoy3(int[][] movies) { Arrays.sort(movies, (a, b) -> a[0] != b[0] ? (a[0] - b[0]) : (a[1] - b[1])); int max = 0; for (int[] movie : movies) { max = Math.max(max, movie[1]); } int[][][] dp = new int[movies.length][max + 1][4]; for (int i = 0; i < movies.length; i++) { for (int j = 0; j <= max; j++) { for (int k = 0; k <= 3; k++) { dp[i][j][k] = -2;// 用-2代表没算过这个过程 } } } return process3(movies, 0, 0, 3, dp); } public static int process3(int[][] movies, int index, int time, int rest, int[][][] dp) { if (index == movies.length) { return rest == 0 ? 0 : -1; } if (dp[index][time][rest] != -2) { return dp[index][time][rest]; } int p1 = process3(movies, index + 1, time, rest, dp); int next = movies[index][0] >= time && rest > 0 ? process3(movies, index + 1, movies[index][1], rest - 1, dp) : -1; int p2 = next != -1 ? (movies[index][1] - movies[index][0] + next) : -1; int ans = Math.max(p1, p2); dp[index][time][rest] = ans; return ans; } // 为了测试 public static int[][] randomMovies(int len, int time) { int[][] movies = new int[len][2]; for (int i = 0; i < len; i++) { int a = (int) (Math.random() * time); int b = (int) (Math.random() * time); movies[i][0] = Math.min(a, b); movies[i][1] = Math.max(a, b); } return movies; } public static void main(String[] args) { int n = 10; int t = 20; int testTime = 10000; System.out.println("测试开始"); for (int i = 0; i < testTime; i++) { int len = (int) (Math.random() * n) + 1; int[][] movies = randomMovies(len, t); int ans1 = maxEnjoy1(movies); int ans2 = maxEnjoy2(movies); int ans3 = maxEnjoy3(movies); if (ans1 != ans2 || ans1 != ans3) { for (int[] m : movies) { System.out.println(m[0] + " , " + m[1]); } System.out.println(ans1); System.out.println(ans2); System.out.println("出错了"); } } System.out.println("测试结束"); } }