DFS练习: POJ2362 POJ2676 POJ2698 POJ3083 POJ3411
POJ2362
package poj2362;
import java.util.Scanner;
/**
* @Author jinjun99
* @Date Created in 2022/10/5 13:22
* @Description
* 用到了定序剪枝,遍历正方形的一条边时,是从n根小棒中选几根,前面跳过的后面不会再挑,
* 将本次选择的小棒编号i加上1传给下一递归,下次递归接着从i+1开始遍历小棒数组。
* 完成当前边再把下标调回0。
* @Since version-1.0
*/
public class Main {
static int side;
static int n;
static int[] sticks;
static int[] check;
static int succeed;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
for (int i = 0; i < num; i++) {
n = sc.nextInt();
sticks = new int[n + 5];
check = new int[n + 5];
for (int j = 0; j < n; j++) {
sticks[j] = sc.nextInt();
}
int sum = 0;
int max = 0;
for (int j = 0; j < n; j++) {
sum += sticks[j];
if (sticks[j]>max){
max = sticks[j];
}
}
side = sum / 4;
if (sum % 4 == 0 && side >= max) {
succeed = 0;
dfs(0,0, 0,0);
if (succeed == 1) {
System.out.println("yes");
} else {
System.out.println("no");
}
} else {
System.out.println("no");
}
}
}
/**
* @param currLen 当前长度
* @param finishNum 当前完成棍子数
*/
private static void dfs(int index,int currLen, int finishNum,int layer) {
if (succeed==0){
for (int i = index; i < n; i++) {
if (currLen + sticks[i] < side && check[i] == 0) {
currLen += sticks[i];
check[i] = 1;
dfs(i+1,currLen, finishNum,layer+1);
check[i] = 0;
currLen -= sticks[i];
}
if (currLen + sticks[i] == side && check[i] == 0) {
finishNum++;
check[i] = 1;
if (finishNum == 3) {
succeed = 1;
return;
}
dfs(0,0, finishNum,layer+1);
finishNum--;
check[i] = 0;
}
}
}
}
}
POJ2676
package poj2676;
import java.util.Scanner;
/**
* @Author jinjun99
* @Date Created in 2022/10/11 15:09
* @Description
* @Since version-1.0
*/
public class Main {
static int n = 10;
static int spaceNum;
static int[][] map;
static boolean[][] row;
static boolean[][] column;
static boolean[][] grid;
/**
* 每行剩余的空位数
*/
static int[] rowSpace;
/**
* 找到一行的解标记为true
*/
static boolean filled;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int m = sc.nextInt();
sc.nextLine();
for (int i = 0; i < m; i++) {
initData();
for (int j = 1; j < n; j++) {
String str = sc.nextLine();
for (int k = 1; k < n; k++) {
int num = str.charAt(k - 1) - '0';
map[j][k] = num;
if (num > 0) {
rowSpace[j]--;
spaceNum--;
row[j][num] = true;
column[k][num] = true;
int g = 3 * ((j - 1) / 3) + (k - 1) / 3 + 1;
grid[g][num] = true;
}
}
}
dfs(spaceNum);
for (int j = 1; j < n; j++) {
for (int k = 1; k < n; k++) {
if (k == n - 1) {
System.out.println(map[j][k]);
} else {
System.out.print(map[j][k]);
}
}
}
}
}
private static void dfs(int sn) {
if (sn==0){
filled = true;
return;
}
int[] index = findIndex();
int x = index[0];
int y = index[1];
int k = 3 * ((x - 1) / 3) + (y - 1) / 3 + 1;
for (int i = 1; i < n; i++) {
if (!row[x][i] && !column[y][i] && !grid[k][i]) {
/*三个条件都满足则填入数字*/
map[x][y] = i;
row[x][i] = true;
column[y][i] = true;
grid[k][i] = true;
rowSpace[x]--;
dfs(sn-1);
/*如果前面的递归填完9行找到一个解,就在这里截断递归和回溯*/
if (filled){
return;
}
rowSpace[x]++;
map[x][y] = 0;
row[x][i] = false;
column[y][i] = false;
grid[k][i] = false;
}
}
}
private static int[] findIndex(){
int temp = 0;
int[] index = new int[4];
for (int i = 1; i < n; i++) {
if (rowSpace[i]>temp){
temp = rowSpace[i];
index[0] = i;
}
}
for (int i = 1; i < n; i++) {
if (map[index[0]][i]==0){
index[1]=i;
}
}
return index;
}
private static void initData() {
map = new int[n + 5][n + 5];
row = new boolean[n + 5][n + 5];
column = new boolean[n + 5][n + 5];
grid = new boolean[n + 5][n + 5];
rowSpace = new int[n];
for (int i = 1; i < n; i++) {
rowSpace[i] = 9;
}
spaceNum = 81;
filled = false;
}
}
/*
(1)用DFS搜索每个空格子。
(2)用位运算记录格子状态。每行、每列、每个九宫格,分别用一个9位的二进制数保存哪些数字还可以填。
对于每个位置,把它在的行,列,九宫格对应的数取 & 运算就可以得到剩余哪些数可以填。并用lowbit(x)取出能填的数。
(3)优化搜索顺序剪枝。从最容易确定数字的行(或列)开始填数,也就是0最少的行(或列);
在后续每个状态下,也选择0最少的行(或列)填数。
(4)可行性剪枝。每格填的数只能是对应行、列和宫中没出现过的。
1
103000509
002109400
000704000
300502006
060000050
700803004
000401000
009205800
804000107
*/
POJ2698
package POJ2698;
import java.util.Scanner;
/**
* @Author jinjun99
* @Date Created in 2022/9/30 13:21
* @Description
* @Since version-1.0
*/
public class Main {
/**
* 案例数
*/
static int n;
/**
* DVD机数
*/
static int k;
/**
* 当前DVD机里的DVD编号
*/
static int[] driver;
/**
* 一个序列的DVD数
*/
static int l;
/**
* DVD序列
*/
static int[] sequence;
/**
* 最小插入次数
*/
static int minInsertions;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
for (int i = 0; i < n; i++) {
k = sc.nextInt();
l = sc.nextInt();
driver = new int[k+5];
sequence = new int[l+5];
for (int j = 0; j < l; j++) {
sequence[j] = sc.nextInt();
}
minInsertions = k;
/*先放k张碟进去*/
for (int j = 0; j < k; j++) {
/*加个保险*/
if (j<l){
driver[j] = sequence[j];
}else {
minInsertions = l;
}
}
if (k<l){
optimalPermutation();
}
System.out.println(minInsertions);
}
}
private static void optimalPermutation() {
/*遍历剩下的DVD序列*/
for (int i = k; i < l; i++) {
/*要取出的DVD机编号*/
int index = 0;
/*当前机内的DVD编号与后面序列中同编号的DVD的间隔*/
int interval = 0;
/*当前DVD编号不在机内*/
boolean outside = true;
/*遍历DVD机*/
for (int j = 0; j < k; j++) {
int dvd = driver[j];
int dist = 0;
/*当前DVD在机内*/
if (dvd==sequence[i]){
outside = false;
break;
}
/*当前机内DVD已不在剩下的序列中*/
boolean end = false;
/*计算当前机内DVD与剩下的序列中最近同编号DVD的距离*/
for (int m = i; m < l; m++) {
if (sequence[m]==dvd){
break;
}else {
dist++;
if (m==l-1){
end = true;
}
}
}
if (dist>interval||end){
index = j;
interval = dist;
}
}
if (outside){
driver[index] = sequence[i];
minInsertions++;
}
}
}
}
POJ3083
package poj3083;
import java.util.LinkedList;
import java.util.Scanner;
/**
* @Author jinjun99
* @Date Created in 2022/10/4 11:21
* @Description 靠左靠右的路径,因为只有一条路,限制方向,不限制长短,可以用dfs或循环。
* 求最短路径,多阶段决策问题求最少决策应该用BFS,因为以前先学的DFS,而且很多地图类题目,下意识用DFS,超时了。
* @Since version-1.0
*/
public class Main {
static int n;
static int w;
static int h;
static char[][] map;
static int[] start;
static int[] end;
static int rightPath;
static int liftPath;
static int minPath;
static int frontDir;
/**
* 左前右后顺序的方向数组
*/
static int[][] leftDir = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
/**
* 右前左后顺序的方向数组
*/
static int[][] rightDir = {{1, 0}, {0, -1}, {-1, 0}, {0, 1}};
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
for (int i = 0; i < n; i++) {
w = sc.nextInt();
h = sc.nextInt();
map = new char[w + 5][h + 5];
start = new int[5];
end = new int[5];
for (int j = 0; j < h; j++) {
String str = sc.next();
for (int k = 0; k < w; k++) {
/*读取地图*/
map[k][j] = str.charAt(k);
/*读取起点和终点坐标*/
if (map[k][j] == 'S') {
start[0] = k;
start[1] = j;
}
if (map[k][j] == 'E') {
end[0] = k;
end[1] = j;
}
}
}
rightPath = 1;
liftPath = 1;
frontDir = getFrontDir();
getLeftOrRightPath(0);
getLeftOrRightPath(1);
minPath = 1;
bfs();
System.out.println(liftPath + " " + rightPath + " " + minPath);
}
}
private static void bfs() {
Node root = new Node(start[0],start[1],1 );
LinkedList<Node> list = new LinkedList<Node>();
list.offer(root);
while (!list.isEmpty()){
Node parent = list.poll();
int childX,childY;
int childStep = parent.step+1;
if (minPath==1||childStep<minPath){
for (int i = 0; i < 4; i++) {
childX = parent.x+leftDir[i][0];
childY = parent.y+leftDir[i][1];
boolean bl1 = childX>=0&&childX<w&&childY>=0&&childY<h;
if (bl1){
if (map[childX][childY]=='E'){
minPath = childStep;
break;
}
if (map[childX][childY]=='.'){
map[childX][childY]='#';
list.offer(new Node(childX,childY,childStep));
}
}
}
}
}
}
static class Node{
int x;
int y;
int step;
public Node(int x, int y, int step) {
this.x = x;
this.y = y;
this.step = step;
}
}
/**
* 获取一直靠左/右墙行走的路径长度
*
* @param searchDir 0是靠左,1是靠右
*/
private static void getLeftOrRightPath(int searchDir) {
/*当前坐标*/
int x = start[0];
int y = start[1];
/*获取与当前正前方相对应的左边方向编号,按照左前右后的方向搜索*/
int nextDir = turnLeft(frontDir);
/*开始靠左或右墙走迷宫*/
while (true) {
for (int i = 0; i < 4; i++) {
int nextX, nextY;
/*下一步坐标*/
if (searchDir == 0) {
nextX = x + leftDir[nextDir][0];
nextY = y + leftDir[nextDir][1];
} else {
nextX = x + rightDir[nextDir][0];
nextY = y + rightDir[nextDir][1];
}
// 防止越界
boolean bl1 = nextX >= 0 && nextY >= 0 && nextX < w && nextY < h;
if (bl1) {
/* 到达终点*/
if (map[nextX][nextY] == 'E') {
if (searchDir == 0) {
liftPath++;
} else {
rightPath++;
}
return;
}
/*下一步可行*/
if (map[nextX][nextY] == '.') {
x = nextX;
y = nextY;
/*如果当前方向可行,则下一步从当前方向相对应的左/右方开始搜索*/
nextDir = turnLeft(nextDir);
if (searchDir == 0) {
liftPath++;
} else {
rightPath++;
}
break;
}
}
/*右转一个方向,按左前右后遍历4个方向*/
nextDir = turnRight(nextDir);
}
}
}
/**
* 左转
*
* @param dir 当前方向
* @return
*/
private static int turnLeft(int dir) {
dir -= 1;
if (dir >= 0) {
return dir;
} else {
return 3;
}
}
/**
* 右转
*
* @param dir 当前方向
* @return
*/
private static int turnRight(int dir) {
dir += 1;
if (dir <= 3) {
return dir;
} else {
return 0;
}
}
/**
* @return 找到起点的正前方的方向号码
*/
private static int getFrontDir() {
int fDir = 0;
int a, b;
for (int j = 0; j < 4; j++) {
a = start[0] + leftDir[j][0];
b = start[1] + leftDir[j][1];
boolean bl = a >= 0 && a < w && b >= 0 && b < h;
if (bl && map[a][b] == '.') {
fDir = j;
break;
}
}
return fDir;
}
}
/*
2
8 8
########
#......#
#.####.#
#.####.#
#.####.#
#.####.#
#...#..#
#S#E####
9 5
#########
#.#.#.#.#
S.......E
#.#.#.#.#
#########
*/
POJ3411
package poj3411;
import java.util.Scanner;
/**
* @Author jinjun99
* @Date Created in 2022/10/17 22:44
* @Description
* @Since version-1.0
*/
public class Main {
static int n;
static int m;
static class Rode{
int a;
int b;
int c;
int p;
int r;
}
static Rode[] rodes;
static int[] visit;
static int minCost = 2000;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
rodes = new Rode[m+5];
visit = new int[m+5];
for (int i = 0; i < m; i++) {
Rode rode = new Rode();
rode.a = sc.nextInt();
rode.b = sc.nextInt();
rode.c = sc.nextInt();
rode.p = sc.nextInt();
rode.r = sc.nextInt();
rodes[i] = rode;
}
dfs(1,0);
if (minCost==2000){
System.out.println("impossible");
}else {
System.out.println(minCost);
}
}
private static void dfs(int city, int cost) {
if (city==n){
if (cost<minCost){
minCost = cost;
}
return;
}
for (int i = 0; i < m; i++) {
int b = rodes[i].b;
if (city == rodes[i].a&&visit[b]<=3){
visit[b]++;
if (visit[rodes[i].c]>0){
dfs(b,cost+rodes[i].p);
}else {
dfs(b,cost+rodes[i].r);
}
visit[b]--;
}
}
}
}
/*
4 5
1 2 1 10 10
2 3 1 30 50
3 4 3 80 80
2 1 2 10 10
1 3 2 10 50
*/