一、路线规划
某公司有M个园区,从0到M-1编号,已知2个园区的距离,描述如下:0 1 3,表示从0号园区到1号园区的距离是3(1到0号园区也是3),已知N段距离,未给出距离的则为不可达,现在有一个员工想从A区出发,走遍所有的园区,同一园区只能够经过一次,请计算该员工的最短距离。
输入
第一行:园区个数M,起始园区编号,已知距离个数N
第二行到N行:第一个数字为起始园区,第二个数字为目的园区,第三个数字为距离,中间使用空格区分。
约束:
0<M<=15,0<N<=45
所有输入数据>=0,距离输入都为有效范围,不用考虑无效输入。距离范围为:[1,1000]
每个园区路径不超过3条
输出
最短距离,如无法完成题目条件,则输出-1
样例
4 0 4
0 1 1
1 2 1
2 3 1
1 3 2
1
2
3
4
5
输出3
解释:从园区0经过园区1,再从园区1到园区2,最后到达园区3,最短距离3
4 0 4
0 1 1
0 2 1
0 3 1
1 2 1
1
2
3
4
5
输出-1
无法从0到3,输出-1
参考代码
使用了DFS解,应该还有更好的解法。leetcode上有类似的题LCP 07. 传递信息
以下代码过了80%的测试用例
package zsh;
import java.util.Scanner;
public class Park {
static boolean flag = false;
static int minDistance = Integer.MAX_VALUE;
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int parkNum = scanner.nextInt();
int start = scanner.nextInt();
int pathNum = scanner.nextInt();
int[][] path = new int[parkNum][parkNum];
for(int i = 0; i < pathNum; i++){
int x = scanner.nextInt();
int y = scanner.nextInt();
int value = scanner.nextInt();
path[x][y] = value;
path[y][x] = value;
}
// int parkNum = 4;
// int start = 0;
// int pathNum = 4;
// int[][] path = {
// {0, 1, 0, 0},
// {1, 0, 2, 1},
// {0, 2, 0, 1},
// {0, 1, 1, 0}
// };
boolean[] isVisit = new boolean[parkNum];
isVisit[start] = true;
int distance = 0;
int visitNum = 1;
dfs(start, path, distance, parkNum, visitNum, isVisit);
if(flag){
System.out.println(minDistance);
}
else{
System.out.println(-1);
}
}
public static void dfs(int cur, int[][] path, int distance, int parkNum, int visitNum, boolean[] isVisit){
if(visitNum == parkNum){
flag = true;
minDistance = Math.min(minDistance, distance);
return;
}
for(int i = 0; i < parkNum; i++) { //for循环结束和isVisit同时确保不在一个点循环
if (path[cur][i] == 0 || isVisit[i] == true) {
continue;
}
isVisit[i] = true;
distance += path[cur][i];
visitNum++;
dfs(i, path, distance, parkNum, visitNum, isVisit);
isVisit[i] = false;
distance -= path[cur][i];
visitNum--;
}
}
}
1.2 上题的变种,注意区别
m个村庄,村庄之间n个公交车线路相连接,现给出所有村庄之间公交路线图及乘坐费用。
小明希望花费最少的钱从村庄A最多经过K次中转到达村庄D。如果没有相关路线,程序返回-1.
输入:4 (村庄个数)
0 (起始地)
3 (目的地)
1 (中转次数)
[[0,1,2],[0,2,4],[1,3,6],[1,2,1],[2,3,2]] (公交路线图及乘坐费用edge = [source, destination, price])
输出 6 从村庄0到村庄3最多经过1次中转,最少花费6
package zsh;
import java.util.Scanner;
public class Park {
static boolean flag = false;
static int minDistance = Integer.MAX_VALUE;
static int pathNum;
public static void main(String[] args){
// Scanner scanner = new Scanner(System.in);
// int parkNum = scanner.nextInt();
// int start = scanner.nextInt();
// int end = scanner.nextInt();
//// int pathNum = scanner.nextInt();
// int maxNum = scanner.nextInt();
// int[][] path = new int[parkNum][parkNum];
// for(int i = 0; i < pathNum; i++){
// int x = scanner.nextInt();
// int y = scanner.nextInt();
// int value = scanner.nextInt();
// path[x][y] = value;
// path[y][x] = value;
// }
int parkNum = 4;
int start = 0;
int end = 3;
pathNum = 1;
int[][] path = {
{0, 2, 4, 0},
{0, 0, 1, 6},
{0, 0, 0, 2},
{0, 0, 0, 0}
};
boolean[] isVisit = new boolean[parkNum];
isVisit[start] = true;
int distance = 0;
int visitNum = 0;
dfs(start, path, distance, parkNum, visitNum, isVisit, end);
if(flag){
System.out.println(minDistance);
}
else{
System.out.println(-1);
}
}
public static void dfs(int cur, int[][] path, int distance, int parkNum, int visitNum, boolean[] isVisit, int end){
if(cur == end && visitNum <= pathNum+1){
flag = true;
minDistance = Math.min(minDistance, distance);
return;
}
for(int i = 0; i < parkNum; i++) { //for循环结束和isVisit同时确保不在一个点循环
if (path[cur][i] == 0){ // || isVisit[i] == true) {
continue;
}
// isVisit[i] = true;
distance += path[cur][i];
visitNum++;
dfs(i, path, distance, parkNum, visitNum, isVisit, end);
// isVisit[i] = false;
distance -= path[cur][i];
visitNum--;
}
}
}
二、逃出生天
在大小为row*col的方格区域地图上,处处暗藏杀机,地图上每一个格子均有一个倒计时转置,当时间变为0时会触发籍贯,使得该格子区域变为一处死地,该区域无法通过,英雄每移动一个格子消耗1s。英雄可以上下左右四个方向移动,请设置一条最佳路线,让英雄最短时间从[0,0]到达[row-1,col-1]离开。
注意:英雄在出生点和出口时,该区域不能为死地。
输入
首行输入单个空格分隔的两个正整数row和col,row代表行数(0<row<=15),col代表列数(0<col<=15)
接下来row行,每一行包含col个以当个空格分隔的数字,代表对应时间的区域倒计时装置设定时间time,单位为秒(0<=time<=100)
输出
英雄从起点到终点的最短用时,若无法到达,则输出-1
样例
输入
3 3
2 3 2
5 1 1
4 5 5
1
2
3
4
输出
4
输入
5 5
3 5 4 2 3
4 5 3 4 3
4 3 5 3 2
2 5 3 3 5
5 3 4 4 3
1
2
3
4
5
6
输出
-1
参考代码
还是DFS问题,过了70%
package zsh;
import java.util.Scanner;
public class IslandTime {
static int minTime = Integer.MAX_VALUE;
static boolean flag = true;
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int row = scanner.nextInt();
int col = scanner.nextInt();
int[][] map = new int[row][col];
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
map[i][j] = scanner.nextInt();
}
}
// int row = 5;
// int col = 4;
// int[][] map = {
// {1, 2, 3, 4},
// {1, 1, 1, 5},
// {9, 8, 7, 6},
// {10, 1, 1, 1},
// {11, 12, 13, 14},
// };
int costTime = 0;
boolean[][] isVisit = new boolean[row][col];
dfs(0, 0, costTime, isVisit, row, col, map);
if(flag){
System.out.println(minTime);
}
else{
System.out.println(-1);
}
}
public static void dfs(int x, int y, int costTime, boolean[][] isVisit, int row, int col, int[][] map){
if(x < 0 || y < 0 || x >= row || y >= col || isVisit[x][y] ==true || map[x][y] < costTime){
return;
}
if(x == (row-1) && y == (col-1)){
minTime = Math.min(costTime, minTime);
flag = true;
return;
}
isVisit[x][y] = true;
dfs(x, y+1, costTime + 1, isVisit, row, col, map);
dfs(x+1, y, costTime + 1, isVisit, row, col, map);
dfs(x,y-1, costTime + 1, isVisit, row, col, map);
dfs(x-1,y, costTime + 1, isVisit, row, col, map);
}
}
package zsh;
import java.util.Scanner;
public class LandMap {
static int maxArea = 0;
static boolean flag = true;
public static void main(String[] args){
// Scanner scanner = new Scanner(System.in);
// int row = scanner.nextInt();
// int col = scanner.nextInt();
// int[][] map = new int[row][col];
// for(int i = 0; i < row; i++){
// for(int j = 0; j < col; j++){
// map[i][j] = scanner.nextInt();
// }
// }
int row = 6;
int col = 6;
int[][] map = {
{1, 1, 1, 1, 2, 1},
{0, 0, 0, 0, 1, 0},
{0, 2, 5, 0, 0, 0},
{0, 1, 2, 0, 0, 0},
{0, 0, 1, 1, 0, 0},
{0, 0, 0, 0, 0, 0},
};
int area = 0;
boolean[][] isVisit = new boolean[row][col];
for(int i = 0; i < row; i++) {
for(int j = 0; j < col; j++) {
if(map[i][j] > 0){
area = dfs(i, j, isVisit, map);
maxArea = Math.max(maxArea, area);
}
}
}
System.out.println(maxArea);
}
public static int dfs(int x, int y, boolean[][] isVisit, int[][] map){
if(x < 0 || y < 0 || x >= map.length || y >= map[0].length || isVisit[x][y] ==true || map[x][y] == 0 ){
return 0;
}
isVisit[x][y] = true;
return map[x][y]
+dfs(x, y+1, isVisit, map)
+dfs(x+1, y, isVisit, map)
+dfs(x,y-1, isVisit, map)
+dfs(x-1,y, isVisit, map);
// area += map[x][y];
//// maxArea = Math.max(maxArea, area);
// isVisit[x][y] = true;
// dfs(x, y+1, isVisit, map, area);
// dfs(x+1, y, isVisit, map, area);
// dfs(x,y-1, isVisit, map, area);
// dfs(x-1,y, isVisit, map, area);
// return area;
}
}
三、求海岛面积,不同于Leecode,每块面积不同
package zsh;
public class LandMap {
static int maxArea = 0;
static boolean flag = true;
public static void main(String[] args){
// Scanner scanner = new Scanner(System.in);
// int row = scanner.nextInt();
// int col = scanner.nextInt();
// int[][] map = new int[row][col];
// for(int i = 0; i < row; i++){
// for(int j = 0; j < col; j++){
// map[i][j] = scanner.nextInt();
// }
// }
int row = 3;
int col = 3;
// int[][] map = {
// {1, 2, 3, 4, 5, 6},
// {0, 0, 0, 8, 7, 0},
// {0, 2, 0, 9, 0, 0},
// {0, 1, 2, 0, 0, 0},
// {0, 0, 1, 1, 0, 0},
// {0, 0, 0, 0, 0, 0},
// };
int[][] map = {
{1, 2, 3},
{0, 4, 0},
{0, 1, 0},
};
int area = 0;
boolean[][] isVisit = new boolean[row][col]; //是否访问过
for(int i = 0; i < row; i++) {
for(int j = 0; j < col; j++) {
if(map[i][j] > 0){
area = dfs(i, j, isVisit, map);
maxArea = Math.max(maxArea, area);
}
}
}
System.out.println(maxArea);
}
public static int dfs(int x, int y, boolean[][] isVisit, int[][] map){
if(x < 0 || y < 0 || x >= map.length || y >= map[0].length || isVisit[x][y] ==true || map[x][y] == 0 ){
return 0;
}
int area = map[x][y];
isVisit[x][y] = true;
area += dfs(x, y+1, isVisit, map);
area += dfs(x+1, y, isVisit, map);
area += dfs(x,y-1, isVisit, map);
area += dfs(x-1,y, isVisit, map);
return area;
}
}
四、 字符串排列
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
示例:
输入:s = "abc"
输出:["abc","acb","bac","bca","cab","cba"]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zi-fu-chuan-de-pai-lie-lcof
package zsh;
import java.util.*;
public class StringSort {
static char[] charArr;
static List<String> list = new ArrayList<>();
static int length = 0;
static int sum = 0;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
charArr = scanner.nextLine().trim().toCharArray();
length = charArr.length;
dfs(0);
System.out.println(sum);
// for(String str : list){
// System.out.println(str);
// }
}
static void dfs(int k){
if(k == length - 1){
// list.add(charArr.toString());
list.add(String.valueOf(charArr));
sum++;
return;
}
Set<Character> set = new HashSet<>();
for(int i = k; i < length; i++){ //反向思维,第一遍过去顺序,递归回来才交换顺序
if(set.contains(charArr[i])){
continue;
}
set.add(charArr[i]);
swap(i, k);
dfs(k + 1);
swap(k, i);
}
}
static void swap(int x, int y){
char temp = charArr[x];
charArr[x] = charArr[y];
charArr[y] = temp;
}
}
五、出租车和步行
小美的最快到达时间
参考 2021-08-15_zzxhqzz的博客-优快云博客
小美现在临时接到一个会议通知,需要立刻赶往对应地点开会。 不妨将小美所在的地点抽象成一个图。小美位于节点x的位置,将要赶往节点y开会。
小美启动了打车软件,该打车软件可以将起点定位在任何一个节点开始叫车。但是,叫车是需要时间的,不同位置叫车的等车时间不同。
这就意味着,考虑到叫车的时间,小美可以不选自己所在的节点叫车,而选择一个附近的点叫车,在等车时间内自行走路到对应的节点以缩短综合时间,更快地赶到目的地开会。
请注意:小美的叫车终点只能是开会处,即此题不考虑通过多次打车来缩短时间,只考虑更改起点带来的时间减少。
下面给出一个简单的例子来帮助你理解:
小美位于节点1,开会的地点位于节点3
节点1和节点2之间有一条汽车通行时长为1,步行通行时间为2的通路;
节点2和节点3之间有一条汽车通行时长为2,步行通行时间为5的道路;
节点1的打车等候时间为10,节点2的打车等候时间为1,节点3的打车等候时间为5
此时,显然小美有如下几种方案:
第一种方案:小美在节点1打车,此时小美需要先等时间10上车,之后花费3的时间抵达节点3,共计花费时长13;
第二种方案:小美在节点2打车,此时小美需要步行时长2抵达节点2,此时汽车司机已经等候在节点2,小美直接上车,通行时长2后抵达节点3。共计花费时长为4。
第三种方案:小美直接步行到节点3(因为节点3是开会地点,显然在节点3打车无意义),此时花费的时长为7。
以上三种方案中,应选第二种方案能最快抵达开会地点。共计花费时长为4。
注意:实际打车过程中,司机会存在客人太久没来上车自行取消的可能,这里为了简化问题,我们假设司机耐心是充分的,可以无限制等候乘客。
输入描述 第一行四个正整数n,m,x,y,空格隔开,其中 n 表示点的数量,点的序号依次表示为 1 到 n;m表示边的数量;x表示小美当前的节点位置,y表示小美开会的节点位置。
接下来 m 行,每行四个正整数,空格隔开,x, y, p, q,表示节点 x 和节点 y 之间有一条汽车通行时长 p,步行通行时长 q 的双向道路。
接下来一行 n 个空格隔开的正整数,第 i 个正整数表示在第i个节点打车所需要花费的等车时间。
输出描述 输出一行一个正整数表示小美最快抵达开会地点的时间。
样例输入
3 2 1 3
1 2 1 2
2 3 2 5
10 1 5
样例输出 4
提示 数据范围和说明
对于全体数据保证p和q(即汽车通行时间和步行时间)都是[1, 50]内的正整数,保证每个点打车的等候时间都是[1, 1000]内的正整数
对于n和m,对于60%的数据,保证 1<= n <= 10, 1 <= m <= 30, 对于100%的数据,保证 1<= n <= 50, 1 <= m <= 200,数据保证没有重复的边。
package zsh;
import java.util.*;
public class TaxiWalk {
static List<List<Integer>> list = new ArrayList<>(); //用来存储每个节点可以和哪些节点相连
static int nodeNum;
public static int[] bfs(int[] dis, int start, int[][] map){
Queue<Integer> queue = new LinkedList<>();
queue.add(start);
while(!queue.isEmpty()){
int cur = queue.poll();
int len = list.get(cur).size();
for (int i = 0; i < len; i++) {
int next = list.get(cur).get(i);
if(dis[next] > (dis[cur] + map[cur][next])){
dis[next] = dis[cur] + map[cur][next];
queue.add(next);
}
}
}
return dis;
}
//递归遍历
public static int[] dfs(int cur, int end, int[][] path, boolean[] isVisit, int[] dis){
if(cur == end){
return dis;
}
for(int i = 0; i < nodeNum; i++) { //for循环结束和isVisit同时确保不在一个点循环
if (path[cur][i] == 0 || isVisit[i] == true) {
continue;
}
isVisit[i] = true;
dis[i] = Math.min(dis[i], dis[cur] + path[cur][i]);
dfs(i, end, path, isVisit, dis);
isVisit[i] = false;
}
return dis;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
nodeNum = scanner.nextInt();
int edge = scanner.nextInt();
int start = scanner.nextInt()-1;
int end = scanner.nextInt()-1;
int[][] mapTaxi = new int[nodeNum][nodeNum];
int[][] mapWalk = new int[nodeNum][nodeNum];
for (int i = 0; i < nodeNum; i++) {
list.add(new ArrayList<>());
}
for (int i = 0; i < edge; i++) {
int x = scanner.nextInt() - 1; //记得减1,题目从1开始
int y = scanner.nextInt() - 1;
list.get(x).add(y);
list.get(y).add(x);
mapTaxi[x][y] = mapTaxi[y][x] = scanner.nextInt();
mapWalk[x][y] = mapWalk[y][x] = scanner.nextInt();
}
int[] wainextime = new int[nodeNum];
for (int i = 0; i < nodeNum; i++) {
wainextime[i] = scanner.nextInt();
}
int[] disTaxi = new int[nodeNum];
int[] disWalk = new int[nodeNum];
Arrays.fill(disTaxi, Integer.MAX_VALUE);
Arrays.fill(disWalk, Integer.MAX_VALUE);
disTaxi[end] = 0; //倒着走
disWalk[start] = 0;
disTaxi = bfs(disTaxi, end, mapTaxi); //从后往前,倒序打车的最短路,最后贪心判断
disWalk = bfs(disWalk, start, mapWalk); //正序 步行的最短路
//递归
// boolean[] isVisit = new boolean[nodeNum];
// disTaxi = dfs(end, start, mapTaxi, isVisit, disTaxi);
// disWalk = dfs(start, end, mapWalk, isVisit, disWalk);
//贪心判断 等待时间 步行出租车混合 巧妙
int minTime = Integer.MAX_VALUE;
minTime = Math.min(minTime, disWalk[end]); //最慢就是完全步行
for(int i = 0; i < nodeNum; i++){
disWalk[i] = Math.max(disWalk[i], wainextime[i]); //在每个节点坐出租车,必须取 等待时间 和 步行到这个节点 的最大值
minTime = Math.min(disWalk[i] + disTaxi[i], minTime); //加上剩余路程的出租车时间(逆序才能这样加)
}
System.out.println(minTime);
}
}
//3 2 1 3
//1 2 1 2
//2 3 2 5
//10 1 5
package zsh;
public class ShortestPath {
static int[] start;
static int[] end;
static int[][] arr;
static boolean[][] isVisit;
static int res = Integer.MAX_VALUE;
static int row;
static int col;
static int line = 0;
public static void main(String[] args) {
row = 3;
col = 5;
arr = new int[][]{{1, 0, 2, 0, 3},
{0, 2, 0, 1, 1},
{0, 3, 0, 0, 0}};
isVisit = new boolean[row][col];
start = new int[]{0, 2};
end = new int[]{1, 1};
arr[start[0]][start[1]] = 0;
dfs(start[0], start[1]);
System.out.println(res);
}
public static void dfs(int x, int y){
if(x == end[0] && y == end[1]){
res = Math.min(res, line);
line--;
return;
}
if(x < 0 || y < 0 || x >= row || y >= col || isVisit[x][y] == true || arr[x][y] != 0){
return;
}
isVisit[x][y] = true;
dfs(x, y + 1);
line++;
dfs(x + 1, y);
line++;
dfs(x, y - 1);
line++;
dfs(x - 1, y);
line++;
// dfs(x + 1, y, line + 1);
// dfs(x, y - 1, line + 1);
// dfs(x - 1, y, line + 1);
}
}
package zsh;
import java.util.Scanner;
public class QuShi1 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String p = scanner.next();
String str = scanner.nextLine();
String[] arr = str.trim().replace("[", "").replace("]", "").replace("\"","").replace(" ","").
split(",");
boolean flag = false;
for (int i = 0; i < arr.length; i++) {
if(isMatch(arr[i], p)){
System.out.print(arr[i]+" ");
flag = true;
}
}
if(flag == false){
System.out.println("Not Match");
}
}
public static boolean isMatch(String s, String p) {
int m = s.length();
int n = p.length();
boolean[][] dp = new boolean[m + 1][n + 1];
dp[0][0] = true;
for (int i = 1; i <= n; ++i) {
if (p.charAt(i - 1) == '*') {
dp[0][i] = true;
} else {
break;
}
}
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (p.charAt(j - 1) == '*') {
dp[i][j] = dp[i][j - 1] || dp[i - 1][j];
} else if ( s.charAt(i - 1) == p.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
}
}
}
return dp[m][n];
}
}
//a.*.com ["a.test.com","a.b.com","b.c.com"]
//a.*.com ["b.c.com","d.e.com"]