DFS
使用递归可以很好地实现DFS
- 不剪枝
import java.util.Scanner;
public class Test1 {
final static int maxn=30;
static int n;//物品件数
static int V;//背包容量
static int maxValue;//最大价值
static int[] w = new int[maxn];//w[i]为每件物品的重量
static int[] c= new int[maxn];//c[i]为每件物品的价值
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n= scanner.nextInt();
V=scanner.nextInt();
for(int i=0;i<n;i++){
w[i]= scanner.nextInt();
}
for(int i=0;i<n;i++){
c[i]= scanner.nextInt();
}
dfs(0,0,0);
System.out.println(maxValue);
}
public static void dfs(int currentIndex,int preSumW,int preSumC){
if(currentIndex==n){//物品编号从0~n-1
if (preSumW<=V&&preSumC>maxValue){
maxValue=preSumC;
}
return;
}
//岔道口
dfs(currentIndex+1,preSumW,preSumC);//当前物品不放入背包
dfs(currentIndex+1, preSumW+w[currentIndex], preSumC+c[currentIndex]);//当前物品放入背包
}
}
- 剪枝
/**
* 剪枝
*/
import java.util.Scanner;
public class Test2 {
final static int maxn=30;
static int n;//物品件数
static int V;//背包容量
static int maxValue;//最大价值
static int[] w = new int[maxn];//w[i]为每件物品的重量
static int[] c= new int[maxn];//c[i]为每件物品的价值
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n= scanner.nextInt();
V=scanner.nextInt();
for(int i=0;i<n;i++){
w[i]= scanner.nextInt();
}
for(int i=0;i<n;i++){
c[i]= scanner.nextInt();
}
dfs(0,0,0);
System.out.println(maxValue);
}
public static void dfs(int currentIndex,int preSumW,int preSumC){
if(currentIndex==n){
return;
}
if(preSumW+w[currentIndex]<=V){//选第currentIndex件物品(是由条件的)
dfs(currentIndex+1,preSumW+w[currentIndex],preSumC+c[currentIndex]);
if(preSumC+c[currentIndex]>maxValue){
maxValue=preSumC+c[currentIndex];
}
}
dfs(currentIndex+1, preSumW, preSumC);//不选currentIndex件物品
}
}
以上一类常见的DFS问题,本质思想就是:给定一个序列,枚举这个序列的所有子序列(可以不连续),然后再从子序列中选择一个“最优子序列”,使它的某个特征是所有子序列中最优的。
dfs的每个分支就对应序列中的各个元素是选择还是不选择
再看一个例子:(并且要记录最优方案)
/**
* 递归实现DFS
* 剪枝
* 并记录最优方案
*/
public class Test4 {
static int N;//N个整数
static int[] nums;//记录N个整数
static int K;//选K个出来
static int X;//K个数的和
static int maxValue;//最大平方和
static ArrayList<Integer> optList=new ArrayList<>();//存放最优方案
static ArrayList<Integer> tempList=new ArrayList<>();//dd存放临时方案
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
N= scanner.nextInt();
K= scanner.nextInt();
X= scanner.nextInt();
nums=new int[N];
for(int i=0;i<N;i++){
nums[i]= scanner.nextInt();
}
dfs(0,0,0,0);
System.out.println(maxValue);
for (Integer integer : optList) {
System.out.print(integer+" ");
}
}
/**
*
* @param currentIndex 当前数字序号
* @param preTotals 之前的数字个数
* @param preX 之前的数字的和
* @param preMax 之前的数字的平方和
*/
public static void dfs(int currentIndex,int preTotals,int preX,int preMax){
if(currentIndex==N){//数字序号为0~N-1
return;
}
if(1+preTotals<=K){//选择当前数 (剪枝叶:只有当 当前选择的数字个数不超过K时才可以选择当前数字)
tempList.add(nums[currentIndex]);
dfs(currentIndex+1,preTotals+1,preX+nums[currentIndex],preMax+nums[currentIndex]*nums[currentIndex]);
if(1+preTotals==K&&preX+nums[currentIndex]==X&&preMax+nums[currentIndex]*nums[currentIndex]>maxValue){//只有当满足条件时才能更新maxValue
maxValue=preMax+nums[currentIndex]*nums[currentIndex];
// optList=tempList;//java集合对象之间写赋值号是浅拷贝,引用同一个对象,这里需要深拷贝
optList.clear();
for (Integer integer : tempList) {
optList.add(integer);
}
}
tempList.remove((Object)nums[currentIndex]);//不加(object)会认为是下标
}
dfs(currentIndex+1,preTotals,preX,preMax);
}
}
每个数可以选择多次:
/**
* 递归实现DFS
* 剪枝
* 并记录最优方案
*/
public class Test5 {
static int N;//N个整数
static int[] nums;//记录N个整数
static int K;//选K个出来
static int X;//K个数的和
static ArrayList<Integer> tempList=new ArrayList<>();//存放临时方案
static ArrayList<Integer> optList=new ArrayList<>();//存放最优方案
static ArrayList<ArrayList<Integer>> allOptLists=new ArrayList<>();//存放所有最优方案
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
N= scanner.nextInt();
K= scanner.nextInt();
X= scanner.nextInt();
nums=new int[N];
for(int i=0;i<N;i++){
nums[i]= scanner.nextInt();
}
dfs(0,0,0);
for (ArrayList<Integer> allOptList : allOptLists) {
System.out.println(allOptList);
}
}
/**
*
* @param currentIndex 当前数字序号
* @param preTotals 之前的数字个数
* @param preX 之前的数字的和
*/
public static void dfs(int currentIndex,int preTotals,int preX){
if(currentIndex==N){
return;
}
if(1+preTotals<=K){//(可以)选择当前数字
tempList.add(nums[currentIndex]);
dfs(currentIndex,preTotals+1,preX+nums[currentIndex]);//每个整数可以选择多次,当前选择了nums[currentIndex],下一回合仍然可以选择nums[currentIndex]
if(1+preTotals==K&&preX+nums[currentIndex]==X){
optList.clear();
ArrayList<Integer> list = new ArrayList<>(); //TODO 1.每次进递归重新分配一个内存地址给list
for (Integer integer : tempList) {
optList.add(integer);
list.add(integer);
}
// allOptLists.add(optList);//TODO 你妈的 这里也是浅拷贝,还是引用的同一个集合对象,导致了最后allOptLists中的各个集合都是一样的,也就是optList
allOptLists.add(list); //TODO 2.则allOptLists每次add进去的就不是同一个集合对象
}
tempList.remove(tempList.size()-1);//这里参数不能再写(Object)nums[currentIndex],因为这里根据值来删除的话,会一下子删掉所有重复的值
}
dfs(currentIndex+1,preTotals,preX);//不选择当前数字
}
}
BFS
BFS一般由队列实现
-
队列
-
增量数组 表示上下左右四个方向
int[] x={0,0,1,-1};
int[] y={1,-1,0,0};
-
boolean型数组inq记录每个位置是否在BFS中已入过队,防止走回头路
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
/**
*BFS
*/
public class Test6 {
final static int maxn=100;
static int m;//矩阵行数 m×n的矩阵
static int n;//列数
static int[][] grid=new int[maxn][maxn];//矩阵
static boolean[][] inq=new boolean[maxn][maxn];//inq[i][j]表示i行j列元素是否入队过 //我觉得对这个题来说可以不需要这个,可以直接把1变0
//增量数组:
static int[] x={0,0,-1,1};
static int[] y={1,-1,0,0};
public static void main(String[] args) {
//初始化矩阵
Scanner scanner = new Scanner(System.in);
m= scanner.nextInt();
n= scanner.nextInt();
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
grid[i][j]= scanner.nextInt();
}
}
int cnt=0;
//统计“块”的个数
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(grid[i][j]==1&&inq[i][j]==false){
cnt++;
bfs(i,j);//去标记相邻的“1”的inq为true,避免重复访问
}
}
}
System.out.println(cnt);
}
public static void bfs(int row,int col){
Queue<Node> queue=new LinkedList<>();
Node node = new Node(row, col);
queue.offer(node);
inq[row][col]=true;
while(!queue.isEmpty()){
Node topNode = queue.poll();
int topNodeRow=topNode.row;
int topNodeCol=topNode.col;
for(int i=0;i<4;i++){
int tempNodeRow=topNodeRow+x[i];
int tempNodeCol=topNodeCol+y[i];
if(judge(tempNodeRow,tempNodeCol)){
queue.offer(new Node(tempNodeRow,tempNodeCol));
inq[tempNodeRow][tempNodeCol]=true;
}
}
}
}
public static boolean judge(int row,int col){
if(row<0||row>=m||col<0||col>=n){
return false;
}
if(grid[row][col]==0||inq[row][col]==true){
return false;
}
return true;
}
}
class Node{
int row;
int col;
public Node(int row,int col){
this.row=row;
this.col=col;
}
}
- 由于BFS是通过层次的顺序来遍历的,因此可以用来求最小步数