搜索 DFS深度优先搜索

1、洛谷 P1363 幻象迷宫

这种恶魔样例究竟是哪个天才想出来的?!!!!!!

6 20
#.##.##.##.##.##.##.
#.##.##.##.##.##.##.
#.##.##.##.##.##.##.
S.#..#..#..#..#..#..
##..#..#..#..#..#..#
#..#..#..#..#..#..##

md,交了好几发都没过,看了一下这个样例,心都凉了。

能想出来这题解的更是天才Orz,

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1500 + 5;
const int dx[6] = {0, 1, -1, 0, 0};
const int dy[6] = {0, 0, 0, 1, -1};

int n, m;
int st_x, st_y;
int vis[MAXN][MAXN][3];
bool fl, a[MAXN][MAXN];
char ch;
//x和y是取过模的坐标,lx和ly是没有取模的坐标
//简单来说就是开两个图,一个无穷大,但坐标映射的和原图一样大的区域内,另一个和原图一样大,只要从某个点出发又走到了这个点,那就显然是可以走无限远的
void dfs(int x, int y, int lx, int ly){
	if(fl) return;
    //如果原图上面走过 并且在无穷大图上面走到了和原图一样位置的点且不是同一次
	if(vis[x][y][0] && (vis[x][y][1] != lx || vis[x][y][2] != ly)){
		fl = 1; return;//标记为能够走无限远
	}
    //将新走到的横纵坐标映射到原图的位置的横纵坐标进行更新 同时将原图上的这点标记为走过
	vis[x][y][1] = lx, vis[x][y][2] = ly, vis[x][y][0] = 1;
    //上下左右走
	for(int i = 1; i <= 4; ++i){
		int xx = (x + dx[i] + n) % n;
		int yy = (y + dy[i] + m) % m;
		int lxx = lx + dx[i], lyy = ly + dy[i];//计算走到点的坐标
        //如果这个地方可以走(不是障碍物)
		if(!a[xx][yy]){
            //如果新到达的点映射在原图上的坐标不同 || 原图没有走过
			if(vis[xx][yy][1] != lxx || vis[xx][yy][2] != lyy || !vis[xx][yy][0]){
				dfs(xx, yy, lxx, lyy);
			}
		}
	}
}
int main(){
	while(cin >> n >> m){
		fl = 0;
		memset(a, 0, sizeof a);
		memset(vis, 0, sizeof vis);
		for(int i = 0; i < n; ++i){
			for(int j = 0; j < m; ++j){
				cin >> ch;
				if(ch == '#') a[i][j] = 1;
				if(ch == 'S') st_x = i, st_y = j;
			}
		}
		dfs(st_x, st_y, st_x, st_y);
		if(fl) puts("Yes");
		else puts("No");
	}
	return 0;
}

2、洛谷 P1378 油滴扩展

搜索每种油滴的情况,将其滴下,计算扩散半径,进而得到扩散面积。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10;
const double PI = 3.1415926535;
bool s[MAXN];
double x[MAXN], y[MAXN], r[MAXN], xa, ya, xb, yb, ansmax;
int n;

double addnew(int i){
	//计算当前油滴中心到达边界的距离
	double s1 = min(abs(x[i] - xa), abs(x[i] - xb)); 
	double s2 = min(abs(y[i] - ya), abs(y[i] - yb));
	double ss = min(s1, s2);
	for(int j = 1; j <= n; ++j){//查找所有油滴 
		if(s[j] == true){//若该油滴已经被滴下
 			double sr = sqrt((x[i] - x[j])*(x[i] - x[j]) + (y[i] - y[j])*(y[i] - y[j]));//计算两油滴中心点的距离
			ss = min(ss, max(sr - r[j], 0.0));//更新该油滴的半径 
		}
	} 
	return ss; 
} 

void dfs(int k, double sum){
	if(k > n){//如果所有油滴都已滴下 
		ansmax = max(ansmax, sum); return;//更新结果并返回 
	}
	for(int i = 1; i <= n; ++i){//遍历所有油滴 
		if(s[i] == false){//如果当前油滴没有被滴下 
			r[i] = addnew(i);
			s[i] = 1;//标记已滴下 
			dfs(k + 1, sum + r[i] * r[i] * PI);
			s[i] = 0;//回溯 
		}
	}
}

int main(){
	double ss;
	cin >> n;
	cin >> xa >> ya >> xb >> yb;
	ss = abs(xa - xb) * abs(ya - yb);//计算总面积
	for(int i = 1; i <= n; ++i){
		cin >> x[i] >> y[i];
	}
	dfs(1, 0);
	printf("%d", int(ss - ansmax + 0.5));
	return 0;
} 
#include <iostream> 
#include <cstdio>
using namespace std;

// 定义棋盘大小
int n;
const int N = 20; // 假设最大棋盘大小为20x20

// 用于标记列、主对角线、副对角线是否已经有皇后
bool row[N], col[N], dg[2 * N], udg[2 * N]; // 调整对角线数组大小为2*N,以确保索引不越界

// 棋盘表示,'.' 表示空位, 'Q' 表示皇后
char g[N][N];

// 深度优先搜索函数
void DFS(int x, int y, int s)
{
    // 如果当前列已经超出范围,则换到下一行的第一列
    if (y == n) {
        y = 0; // 重置列索引为0
        x++;   // 移动到下一行
        // 立即递归调用,处理下一行
        DFS(x, y, s);
        return; // 退出当前函数,因为这一行的所有位置都已经尝试过
    }

    // 如果当前行已经超出范围,说明所有行都已经处理完毕
    if (x == n) {
        // 如果放置的皇后数量等于n,即找到一个解
        if (s == n) {
            // 输出棋盘状态
            for (int i = 0; i < n; i++)
                puts(g[i]); // 打印当前行
            puts(""); // 打印完一个解后换行
        }
        return; // 退出当前函数,因为所有行都已经处理完毕
    }

    // 尝试在当前位置放置皇后
    // 只有当列、主对角线、副对角线都没有其他皇后时才放置
    if (!row[x] && !col[y] && !dg[x + y] && !udg[n - 1 + x - y]) {
        // 放置皇后并标记该行、列、对角线已被占用
        g[x][y] = 'Q';
        row[x] = col[y] = dg[x + y] = udg[n - 1 + x - y] = true;

        // 继续递归地尝试放置下一个皇后
        DFS(x, y + 1, s + 1);

        // 回溯:移除皇后并恢复标记
        row[x] = col[y] = dg[x + y] = udg[n - 1 + x - y] = false;
        g[x][y] = '.';
    }

    // 递归调用:跳过当前位置,继续尝试下一个位置
    DFS(x, y + 1, s);
}

int main()
{
    // 输入n皇后问题中的n值
    cout << "请输入n皇后问题中的n值: ";
    cin >> n;

    // 初始化棋盘,全部设置为空位
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            g[i][j] = '.'; // 使用'.'表示空位

    // 开始深度优先搜索,从棋盘的第一个位置开始
    DFS(0, 0, 0); // 从第0行第0列开始,初始已放置皇后的数量为0

    return 0;
}
posted @ 2024-09-16 19:23  xiaoluosibky  阅读(28)  评论(0)    收藏  举报