DFS算法练习 POJ1111; POJ1129; POJ2245; POJ2657
POJ1111:
import java.util.Scanner;
/**
* @Author jinjun99
* @Date Created in 2022/9/27 9:49
* @Description
* @Since version-1.0
*/
public class Main {
/**
* 行
*/
static int r;
/**
* 列
*/
static int c;
/**
* 初始坐标
*/
static int x;
static int y;
/**
* 图像数组
*/
static char[][] img;
/**
* 标记数组
*/
static int[][] mark;
/**
* 周长
*/
static int perimeter;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()){
String str = sc.nextLine();
String[] s = str.split(" ");
r = Integer.parseInt(s[0]);
c = Integer.parseInt(s[1]);
x = Integer.parseInt(s[2])-1;
y = Integer.parseInt(s[3])-1;
if (r==0 && c==0 && x==-1 && y==-1) {
break;
}
img = new char[r][c];
mark = new int[r][c];
for (int i = 0; i < r; i++) {
String s1 = sc.nextLine();
char[] c1 = s1.toCharArray();
for (int j = 0; j < c; j++) {
img[i][j] = c1[j];
}
}
perimeter = 0;
dfs(x,y);
System.out.println(perimeter);
}
}
/**
* 方向数组
*/
private static int[] dirX = {0,1,0,-1,-1,1,-1,1};
private static int[] dirY = {1,0,-1,0,-1,1,1,-1};
private static void dfs(int x, int y) {
/*dfs所有'X'*/
if (img[x][y]=='X'&&mark[x][y]==0){
mark[x][y]=1;
for (int i = 0; i < 8; i++) {
int a = x+dirX[i];
int b = y+dirY[i];
boolean bl1 = a>=0&&b>=0&&a<r&&b<c;
/*如果出界或者是'.'*/
if (!bl1 || img[a][b] == '.'){
/*累计边长*/
if (i<4){
perimeter++;
}
}else {
dfs(a,b);
}
}
}
}
}
POJ1129:
import java.util.Scanner;
/**
* @Author jinjun99
* @Date Created in 2022/9/24 17:49
* @Description
* @Since version-1.0
*/
public class Main {
/**
* 中继器数量
*/
static int n;
/**
* 中继器地图数组
*/
static int[][] map;
/**
* 频道分配数组
*/
static int[] distribute;
/**
* 用来记录频道数为2,3,4时分别的分配方案数
*/
static int[] scheme = new int[3];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()){
/*获取第一个数字,即中继器数量*/
n=sc.nextInt();
/*如果数量为0,则结束*/
if (n==0){
break;
}
/*初始化中继器地图数组和频道数组*/
map = new int[n][n];
distribute = new int[n];
scheme = new int[3];
boolean side = false;
/*接收一组数据输入,给数组赋值*/
for (int i = 0; i < n; i++) {
String str = sc.next();
/*每个中继器按字母表顺序用字母表示,可以用第i个字母-第一个
字母A,利用ASCII码之差得到对应字母在字母表中的序数,*/
int charNum = str.charAt(0) - 'A';
/*获取第一个字母表示的中继器相邻的其他中继器*/
for (int j = 2; j < str.length(); j++) {
/*获取字母对应的序数*/
int adja = str.charAt(j)-'A';
map[charNum][adja]=1;
map[adja][charNum]=1;
side=true;
}
}
int channel = 1;
if (side){
dfs(0,0,distribute);
/*排错点1:*/
/*System.out.println(Arrays.toString(scheme));*/
for (int i = 0; i < 3; i++) {
if (scheme[i]!=0){
channel=i+2;
System.out.println(channel+" channels needed.");
break;
}
}
}else {
System.out.println("1 channel needed.");
}
}
}
/**
* @param r 当前中继器编号
* @param c 当前子树能使用的频道数
* @param d 当前的频道安排情况
* @return
*/
private static void dfs(int r,int c,int[] d){
if (r==0){
for (int i = 2; i <= 4; i++) {
d=new int[n];
dfs(1,i,d);
}
}else {
if (r==n+1){
scheme[c-2]++;
return;
}
/*遍历当前能使用的频道数*/
for (int i = 1; i <= c; i++) {
/*对第r个中继器安排i频道*/
d[r-1]=i;
if (satisfied(r,c,d)){
/*排错点2:*/
/* System.out.println(r+""+c+Arrays.toString(d)+Arrays.toString(scheme));*/
dfs(r+1,c,d);
}
/*回溯省略,下一层循环自动刷新*/
}
}
}
/**
* @param r 当前中继器编号
* @param c 当前子树能使用的频道数
* @param d 当前的频道安排情况
* @return
*/
private static boolean satisfied(int r,int c,int[]d){
/*剪枝条件,如果当前限制的频道数(或前一个限制)还未找到一个符合条件的方案*/
boolean condition = (c==2&&scheme[c-2]==0)||(c>2&&scheme[c-2]==0&&scheme[c-3]==0);
if (condition){
/*遍历地图找到当前中继器邻接的其他中继器,依次对比是否符合条件*/
for (int i = 0; i < n; i++) {
if (map[r-1][i]==1&&d[r-1]==d[i]){
/*排错点3:*/
/*System.out.println("r-1="+(r-1)+"; i="+i+"; d[r-1]="+d[r-1]+"; d[i]="+d[i]+"; map[r-1][i]="+map[r-1][i]);*/
return false;
}
}
return true;
}
return false;
}
}
POJ2245:
import java.util.ArrayList;
import java.util.Scanner;
/**
* @Author jinjun99
* @Date Created in 2022/9/27 12:52
* @Description
* @Since version-1.0
*/
public class Main {
/**
* 集合长度
*/
static int k;
/**
* 集合
*/
static int[] set;
/**
* 固定取6个数
*/
static int m = 6;
/**
* 所有子集
*/
static ArrayList<int[]> sub;
/**
* 当前子集
*/
static int[] currSub;
/**
* 被选过的数
*/
static boolean[] selected;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()){
/*数据输入和初始化*/
String str = sc.nextLine();
String[] s1 = str.split(" ");
k = Integer.parseInt(s1[0]);
if (k==0){
break;
}
set = new int[k];
currSub = new int[m];
selected = new boolean[k];
sub = new ArrayList<int[]>();
for (int i = 0; i < k; i++) {
set[i] = Integer.parseInt(s1[i+1]);
}
/*搜索*/
dfs(0);
/*打印*/
for (int i = 0; i < sub.size(); i++) {
int[] subSetI = sub.get(i);
for (int j = 0; j < m; j++) {
if (j==m-1){
System.out.println(subSetI[j]);
}else {
System.out.print(subSetI[j]+" ");
}
}
}
System.out.println("");
}
}
/**
* @param l 解空间树的层数,当前子集的第几个数
*/
private static void dfs(int l) {
if (l==m){
/*到达叶子节点,放入子集集合中*/
int[] sub1 = new int[m];
System.arraycopy(currSub, 0, sub1, 0, m);
sub.add(sub1);
return;
}
for (int i = 0; i < k; i++) {
/*当前set[i]没被选过并且大于当前子集的前一个数(字典序)*/
boolean bl = !selected[i]&&(l==0||(l>0&&set[i]>currSub[l-1]));
if (bl){
/*填入当前子集,并锁定set中的当前数字*/
currSub[l]=set[i];
selected[i]=true;
dfs(l+1);
/*回溯*/
selected[i]=false;
currSub[l]=0;
}
}
}
}
POJ2657:
import java.util.Scanner;
/**
* @Author jinjun99
* @Date Created in 2022/9/27 16:32
* @Description
* @Since version-1.0
*/
public class Main {
/**
* 圆环格数
*/
static int n;
/**
* 目标编号
*/
static int z;
/**
* 阻碍标记数组
*/
static boolean[] m;
/**
* 找到目标
*/
static boolean succeed;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()){
String str = sc.nextLine();
String[] s = str.split(" ");
/* if (s[0]==" "){
break;
}*/
n = Integer.parseInt(s[0]);
z = Integer.parseInt(s[1]);
m = new boolean[n];
int t = Integer.parseInt(s[2]);
if (t!=0){
String str2 = sc.nextLine();
String[] s2 = str2.split(" ");
/*标记阻碍格*/
for (int i = 0; i < t; i++) {
m[Integer.parseInt(s2[i])-1]=true;
}
}
succeed = false;
for (int i = 1; i < n; i++) {
dfs(0,i);
if (succeed){
System.out.println(i);
break;
}
}
}
}
/**
* @param index 当前下标
* @param k 当前子树的k
*/
private static void dfs(int index, int k) {
/*找到目标*/
if (index==z-1){
succeed = true;
return;
}
/*遇到阻碍块或者重复块(说明会一直重复跳不到k),直接结束当前分支*/
if (m[index]){
return;
}
/*标记当前块*/
m[index]=true;
/*跳跃下一步,如果出界就求余循环*/
if (index+k<n){
dfs(index+k,k);
}else {
dfs((index+k)%(n-1),k);
}
/*回溯*/
m[index]=false;
}
}
import combine.Combine01;
/**
* @Author jinjun99
* @Date Created in 2021/12/4 14:57
* @Description
* @Since version-1.0
*/
public class Demo01 {
private static int n = 4;
private static char[][] checkerboard = {
{'b','w','w','b'},
{'b','b','w','b'},
{'b','w','w','b'},
{'b','w','w','w'}
};
private static char[][] checkDemo;
public static void main(String[] args) {
flipGame();
if (fea){
System.out.println(leastFlipNum);
}else {
System.out.println("impossible");
}
}
private static int currFlipNum = 0;
private static int leastFlipNum = 0;
private static void flipGame(){
//第一行翻几个
for (int i = 0; i <= n; i++) {
//求组合
Combine01 cb = new Combine01();
int size= cb.getCombine(n,i);
for (int j = 0; j < size; j++) {
//初始化
checkDemo = charArrCopy(checkerboard,n);
currFlipNum = 0;
for (int k = 0; k < i; k++) {
flip(cb.combineSet[j][k]-1,0);
}
currFlipNum+=i;
flipNextRow();
}
}
}
private static boolean fea = false;
private static void flipNextRow(){
for (int i = 1; i < n; i++) {
for (int j = 0; j < n; j++) {
if (checkDemo[j][i-1]=='b'){
flip(j,i);
currFlipNum++;
}
}
}
boolean bl = true;
for (int i = 0; i < n; i++) {
if (checkDemo[i][n-1]=='b'){
bl = false;
break;
}
}
if (bl&&(currFlipNum<leastFlipNum||leastFlipNum==0)){
fea = true;
leastFlipNum = currFlipNum;
}
}
private static int[] dirX = {0,1,0,-1};
private static int[] dirY = {-1,0,1,0};
private static void flip(int x, int y){
for (int i = 0; i < 5; i++) {
if (i==4){
if (checkDemo[x][y]=='b'){
checkDemo[x][y]='w';
}else {
checkDemo[x][y]='b';
}
continue;
}
int a = x+dirX[i];
int b = y+dirY[i];
if (a>=0&&b>=0&&a<n&&b<n){
if (checkDemo[a][b]=='b'){
checkDemo[a][b]='w';
}else {
checkDemo[a][b]='b';
}
}
}
}
private static char[][] charArrCopy(char[][] c,int n){
char[][] temp = new char[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
temp[i][j] = c[i][j];
}
}
return temp;
}
}
求组合:
/**
* @Author jinjun99
* @Date Created in 2021/12/3 13:53
* @Description
* @Since version-1.0
*/
public class Combine01 {
/**
* 记录所有的组合,解空间
*/
public int[][] combineSet = new int[1000][1000];
/**
* 记录组合数,解空间下标
*/
int index1 = 0;
/**
* 临时解 防止一个解中的选择重复
*/
int[] b;
/**
* 存储一个当前解
*/
int[] cCombine;
public Combine01() {
}
public static void main(String[] args) {
Combine01 combine01 = new Combine01();
combine01.getCombine(3,2);
System.out.println(combine01.index1);
}
/**
* 初始化成员变量,调用dfs求组合方法,返回组合树
* @param n
* @param m
* @return
*/
public int getCombine(int n, int m){
b = new int[n];
cCombine = new int[m];
dfs(0,n,m);
return index1;
}
private void dfs(int lev,int n,int m){
if (lev == m){
if (index1 == 0||feasibility(m) == 1){
for (int i = 0; i < m; i++) {
combineSet[index1][i]= cCombine[i];
}
index1++;
}
return;
}
for (int i = 0; i < n; i++) {
if (b[i] == 0){
b[i] = 1;
cCombine[lev] = i+1;
dfs(lev+1,n,m);
b[i] = 0;
}
}
}
private int feasibility(int m){
for (int i = 0; i < index1; i++) {
int sum = 0;
for (int j = 0; j < m; j++) {
for (int l = 0; l < m; l++) {
if (combineSet[i][j]== cCombine[l]){
sum++;
}
}
}
if (sum==m){
return 0;
}
}
return 1;
}
/**
* 求组合数
* @param n
* @param m
* @return
*/
public static int combineNum(int n,int m){
return factorial(n)/(factorial(m)*factorial(n-m));
}
/**
* 求阶乘
* @param n
* @return
*/
public static int factorial(int n){
if (n<=1){
return 1;
}
return n*factorial(n-1);
}
}