文章目录
- 第一题 HDU 1241 Oil Deposits
- 第二题 HDU 2553 N皇后问题
- 第三题 HDU 1181 变形课
第一题 HDU 1241 Oil Deposits
题目主要信息
- 给定一个二维字符数组,由 * 和 @ 两种字符组成,* 表示正常土地,@表示油田
- 如果多个 @ 能连在一起(上、下、左、右、左上、右上、左下、右下,一共八个方向),连在一起的 @ 算一片“油田”
- 计算二维字符数组中有几片“油田”
思路
遍历二维数组,找到第一个@,然后进行深度优先搜索,检查当前@的八个方向是否还有@,每访问过一个@以后,用vis数组进行标记,避免重复计算
代码
import java.util.Arrays;
import java.util.Scanner;
public class Main {
private int row, col;
private char[][] map;
private boolean[][] vis;
private int cnt;
private int[][] dir = new int[][]{{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};
public static void main(String[] args) {
new Main().solve();
}
public void solve() {
Scanner in = new Scanner(System.in);
while (in.hasNext()) {
row = in.nextInt();
col = in.nextInt();
in.nextLine();
if (row == 0 && col == 0) {
return;
}
//初始化
map = new char[row][col];
vis = new boolean[row][col];
for (int i = 0; i < row; i++) {
//输入数据
map[i] = in.nextLine().toCharArray();
//初始化vis数组
Arrays.fill(vis[i], false);
}
cnt = 0;
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
//没有访问过
if (!vis[i][j] && map[i][j] == '@') {
dfs(i, j);
cnt++;
}
}
}
System.out.println(cnt);
}
}
public void dfs(int x, int y) {
if (x < 0 || x >= row || y < 0 || y >= col) {
return;
}
if (vis[x][y]) {
return;
}
if (map[x][y] == '@') {
//标记该位置访问过
vis[x][y] = true;
//8个方向
for (int i = 0; i < 8; i++) {
dfs(x + dir[i][0], y + dir[i][1]);
}
}
}
}
第二题 HDU 2553 N皇后问题
题目链接
题目主要信息
- 在N*N的棋盘上放置N个皇后,使得她们不相互攻击
- 即任意两个皇后不能在同一行,同一列,或45°和-45°的对角线上
- 计算给定N,求出有多少种放法
- N的范围:[1,10]
思路
用一维数组pos来表示每一行存放皇后的位置,下标表示第几行,如下标为0时,表示现在正在安排第一行的皇后位置,pos[0]表示第一行的皇后在第几列
例如,n=8,目前需要放置第四行的皇后位置,肯定是从第一列到第八列这八个位置分别检查与前三行的三个皇后的位置是否冲突,如果冲突,则继续检查下一列,如果检查完所有的列,都没有满足条件,那么返回到上一行,修改上一行皇后的位置。
check函数的作用是,检查如果在某一行,某一列放置皇后,是否会与前面几行皇后冲突,如果冲突,返回false,如果不冲突,返回true
因为题目中N的范围比较小,[1,10],所以提前计算出所有N的结果,存储在数组中,避免在N为9或10这样较大数字时,运行超时
代码
import java.util.Scanner;
public class Main {
private int n;
//存储每个皇后的位置
private int[] pos;
//有几种摆法
private int cnt;
//存储结果
private int[] res = new int[11];
public static void main(String[] args) {
new Main().solve();
}
private void solve() {
for (int i = 1; i <= 10; i++) {
pos = new int[i];
cnt = 0;
n = i;
dfs(0);
res[i] = cnt;
}
Scanner in = new Scanner(System.in);
while (in.hasNext()) {
n = in.nextInt();
if (n == 0) {
return;
}
System.out.println(res[n]);
}
}
private void dfs(int x) {
if (x == n) {
cnt++;
return;
}
for (int i = 0; i < n; i++) {
if (check(x, i)) {
pos[x] = i;
dfs(x + 1);
}
}
}
private boolean check(int depth, int position) {
for (int i = depth - 1; i >= 0; i--) {
if (Math.abs(pos[i] - position) == Math.abs(i - depth)) {
return false;
}
if (pos[i] == position) {
return false;
}
}
return true;
}
}
第三题 HDU 1181 变形课
题目链接
题目主要内容
找出是否存在多个单词相连,要求第一个单词是字母b开头,最后一个单词是m结尾
例如,big-got-them
找到的话,输出Yes.,否则,输出No.
思路
用一个足够大的数组words去存储单词。
用一个和words一样的数组标记某一个单词是否已经被用过。
index用来记录一共有多少个单词。
flag用来标记是否找到了一个单词序列,满足第一个单词的第一个字母是b,最后一个单词的最后一个字母是m。
由题目可知,当输入0时,表示一组输入输入结束,这时就可以进行搜索,当输出完Yes或No以后,需要把上面的变量“归零”,重置为初始化的状态。
代码
import java.util.Arrays;
import java.util.Scanner;
public class Main {
private int maxn = 10000;
private String[] words;
private boolean[] vis;
private int index;
private boolean flag;
public static void main(String[] args) {
new Main().solve();
}
private void solve() {
Scanner in = new Scanner(System.in);
String word;
index = 0;
flag = false;
vis = new boolean[maxn];
words = new String[maxn];
while (in.hasNext()) {
word = in.next();
if (!"0".equals(word)) {
words[index++] = word;
continue;
}
for (int i = 0; i < index; i++) {
if ('b' == words[i].charAt(0)) {
dfs(i);
if (flag) {
System.out.println("Yes.");
break;
}
}
}
if (!flag){
System.out.println("No.");
}
index = 0;
flag = false;
vis = new boolean[maxn];
words = new String[maxn];
}
}
private void dfs(int pos) {
//如果已经找到由b变成m的方法
if (flag) {
return;
}
//如果这个单词已经被访问过
if (vis[pos]) {
return;
}
//获取最后一个字符
char lastChar = words[pos].charAt(words[pos].length() - 1);
if (lastChar == 'm') {
flag = true;
return;
}
vis[pos] = true;
for (int i = 0; i < index; i++) {
if (!vis[i] && lastChar == words[i].charAt(0)) {
dfs(i);
}
}
vis[pos] = false;
}
}