算法提高-搜索-DFS之连通性模型 DFS之搜索顺序

DFS之连通性模型

DFS有两种保存结果的方法,1.保存在全局(马走日),2.保存在dfs里面返回(暂时我还不会)
DFS只能保证可以搜到,但是不能保证是最短的
这题debug了好久,根本原因是我的dx和dy写错了。。。

AcWing 1112. 迷宫

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 110;

int T, n, xa, ya, xb, yb;
char g[N][N];
bool st[N][N]; 



bool dfs(int x, int y)
{
    
    
    if (g[x][y] == '#') return false;
    if (x == xb && y == yb) return true;
    
   
    st[x][y] = true;//保证不会搜到重复的点,
    //因为系统帮我们维护了一个栈存储下我们遍历的每个状态,方便我们回溯回上一层是继续遍历赏一层的状态可以遍历到的点
    //保证每个点都会搜到,
    
    int dx[4] = {
    
    -1, 0, 0, 1};
    int dy[4] = {
    
    0, 1, -1, 0};
    
    for (int i = 0; i < 4; i ++ )
    {
    
    
        int a = x + dx[i], b = y + dy[i];
        if (a < 0 || a >= n || b < 0 || b >= n) continue;
        if (st[a][b]) continue;//这一步保证了我们不会搜到重复的点
        if (dfs(a, b)) return true; //这里其实相当于入栈操作
    }
    return false;
}




int main ()
{
    
    
    scanf("%d", &T);
    while (T -- )
    {
    
    
        memset(st, 0, sizeof st);//必须要写在这一步,因为是多组测试数据,需要置0
        scanf("%d", &n);
        
        for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);
        
        scanf("%d%d%d%d", &xa, &ya, &xb, &yb);
        if (dfs(xa, ya)) puts("YES");
        else puts("NO");
    }
    
    return 0;
}

AcWing 1113. 红与黑

#include <iostream>
#include <cstring>

using namespace std;

// ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);

const int N = 22;

int  n, m;
char g[N][N]; 
int st[N][N];

int dfs(int x, int y)
{
    
    
    int cnt = 1;//我还纳闷,如果全局变量cnt怎么靠cnt += dfs(a, b)计数的
                //原来是在每次合法的递归中(遍历的时候会判断当前要递归的坐标是否合法)
                //cnt都是1,然后一层一层返回1,并标记当前坐标被遍历过了
                //最终统计出所有黑瓷砖的数量,不重不漏
    st[x][y] = true;
    
    int dx[4] = {
    
    -1, 0 ,0 ,1};
    int dy[4] = {
    
    0, -1, 1, 0};
    for (int i = 0; i < 4; i ++ )
    {
    
    
        int a = x + dx[i], b = y + dy[i];
        if (g[a][b] != '.') continue;
        if (st[a][b]) continue;
        cnt += dfs(a, b);
    }
    return cnt;
}

int main ()
{
    
    
    while(cin >> m >> n, n || m)//很巧妙的标准输入,题目说当在一行中读入的是两个零时,表示输入结束,
    {
    
                               //并且有多组测试数据,只有到00 的时候才是数据结束
        for (int i = 0; i < n; i ++ ) cin >> g[i];
        
        int x, y;
        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < m; j ++ )
                if (g[i][j] == '@')
                {
    
    
                    x = i, y = j;
                }
        memset(st, 0, sizeof st);//多组数据, 所以每次都要置0
        cout << dfs(x, y) << endl;
    }
    
    return 0;
}

DFS之搜索顺序

AcWing 1116. 马走日

dfs的时候如何用全局变量收集结果

#include <iostream>
#include <cstring>

using namespace std;

const int N = 9 + 1;
int n, m, x, y;
int ans;//有多少种路径
bool st[N][N];

void dfs(int x, int y, int cnt)
{
    
    
//这里没有判断是否有失败的情况,因为我们用st数组保证了我们只要按照我们设定的st==true规则一定可以找到一个结果
    if (cnt == n * m)
    {
    
    
        ans ++;
        return ;
    }
    st[x][y] = true;
    int dx[8] = {
    
    -1, -2, -2, -1, 1, 2, 2, 1}, dy[8] = {
    
    -2, -1, 1, 2, 2, 1, -1, -2};//遍历规则,只要保证能把所有情况都遍历到即可
                                                                                   //不重不漏即可    
    
    for (int i = 0; i < 8; i ++ )
    {
    
    
        int a = x + dx[i], b = y + dy[i];
        if (a < 0 || a >= n || b < 0 || b >= m) continue;
        if (st[a][b]) continue;
        dfs(a, b, cnt + 1);
    }
    st[x][y] = false;//前面递归递归完成功收集结果后,要记得恢复现场
}
int main ()
{
    
    
    int T;
    cin >> T;
    while (T -- )
    {
    
    
        cin >> n >> m >> x >> y;
        ans = 0;//多组数据,置0
        memset(st, 0, sizeof st);//多组数据,置0
        dfs(x, y, 1);
        cout << ans << endl;
    }
   
    return 0;
}

AcWing 1117. 单词接龙

#include <iostream>
#include <unordered_map>
#include <algorithm>

using namespace std;

const int N = 25;

int n;
char start;
string word[N];
int g[N][N];
int used[N];
int ans;

void dfs(string dragon, int last)//不论能否找到结果,反正ans取max,总能找到一条路可以把所有单词串起来并且接龙最长
{
    
    
    
    ans = max((int)dragon.size(), ans);//不知道这里为什么要强转一下
    used[last] ++ ;
    
    for (int i = 0; i < n; i ++ )
    {
    
    
        if (g[last][i] && used[i] < 2)
        {
    
    
            /*
            dragon += word[i].substr(g[last][i]);//不能这么写,除非后面跟着一个回溯
            dfs(dragon, i);
            dragon -= word[i].substr(g[last][i]);//可以这么写,但是我不知道string如何-=
            */  
            dfs(dragon + word[i].substr(g[last][i]), i);//相当于编译器手动帮我们进行回溯操作了
        }
    }
    used[last] --;//回溯
}
int main()
{
    
    
    cin >> n;
    for (int i = 0; i < n; i ++ ) cin >> word[i];
    
    cin >> start;
    
    //打表,预处理一下可以接龙接的数组
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n; j ++ )
        {
    
    
            string a = word[i], b = word[j];
            for (int k = 1; k < min(a.size(), b.size()); k ++ )//k从1开始,至少得有一个字符重合
            {
    
    
                if (a.substr(a.size() - k, k) == b.substr(0, k))
                {
    
    
                    g[i][j] = k;//正好直接将k存进去,记录第i个单词和第j个单词可以重合的长度为多少
                    break;//找到一个就可以break
                }
            }
        }
    
    for (int i = 0; i < n; i ++ )//找到一个开头字符为start的单词
        if (word[i][0] == start)
            dfs(word[i], i);
    cout << ans;
    return 0;
}

AcWing 1118. 分成互质组

猜你喜欢

转载自blog.csdn.net/chirou_/article/details/130981947