深度优先搜索DFS入门与实战(C++)


方便自己预习也帮大佬们复习
下列代码均为AC代码,请放心食用

概述

概念

dfs是一种通过递归遍历图与树的较为全面的算法,应用较为广泛,在遍历到不符合规定时取消遍历并不断向前回溯至出发位置,效率较低,目的是全面无遗漏的遍历,可以通过记忆化与剪枝进行优化。

树遍历

过程解析:

1
2
3
4
5
6
7
8
9
10

先序遍历:1.2.4.5.8.3.6.9.10.7
dfs理解:
进入结点1(2.3)进入子结点2(4.5)再进入孙节点4发现4是最后一个,这条路结束[1.2.4]。
再开始退一步进入子结点2(4.5)中进入孙结点5(8),再进入曾孙结点8发现8是最后一个,这条路结束[5.8]
再开始,退一步5(遍历完成),退一步2(遍历完成),退一步1(2.3)开始遍历子结点3(6.7)再进入孙结点6(9.10)再进入9发现是最后一个,这条路结束[3.6.9]
再开始退一步进入子节点6(9.10)出10,结束[10]
再开始,退一步6(遍历完成),退一步3(6.7)出7,结束[7]

图遍历
1 2
3 4
5 6
7 8

若要列出从1到6的所有走法(只能向上或向右移动),便得出下面的类树形结构

1
2
3
4
5
6
7
8

由于深度优先搜索讲究深度,可以很轻易构建树形结构模型

线性遍历

线性枚举所有可能,这里给一道类01背包的题来辅助说明

zzuli测试链接

题目描述:
有n个小球,每个小球都有一个随机编号。你可以执行以下操作。
从这n个小球挑选出几个小球,将这些小球上面的编号相加,这样我们就得到了一个数字。
令mi为无法通过以上操作得到的最小正整数,输出mi-1。

输入描述:
第一行一个数字T,表示T组测试数据。(0<T≤10)
每组数据有两行输入。
第一行一个整数n,表示小球的个数。(1≤n≤ 10)
第二行n个整数a1,a2,a3,…,an(1≤i≤n,0<ai≤1000),表示小球上面的编号。

输出描述:
输出每组数据的mi-1

样例:
输入
3
3
1 2 3
3
3 3 3
3
1 1 1
输出
6
0
3

可用以下树形结构来说明枚举情况,深度等于第i个球的枚举情况,yes表示选,no表示不选(先只枚举四种)

start
yes
yes
yes
yes
no
no
no
no
结果

先想想代码怎么实现
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

思路1:十重循环
每种小球都有取或不取两种情况,对每个小球逐个枚举即可,时间复杂度为O(2^n)
#include <stack>
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <cmath>
#include <unordered_map>
#define rep1(i, a, n) for (int i = a; i <= n; i++)
#define rep2(i, a, n) for (int i = a; i >= n; i--)
#define mm(a, b) memset(a, b, sizeof(a))
#define elif else if
typedef long long ll;
using namespace std;
int num[10005];
int x[12];
int main()
{
    
    
    int T;
    cin >> T;
    while (T--)
    {
    
    
        mm(num, 0);
        mm(x, 0);
        int n;
        cin >> n;
        rep1(i, 0, n - 1)
                cin >>x[i],num[x[i]] = 1;
        //十重循环枚举全部情况
        rep1(a, 0, 1)
        rep1(b, 0, 1)
        rep1(c, 0, 1)
        rep1(d, 0, 1)
        rep1(e, 0, 1)
        rep1(f, 0, 1)
        rep1(g, 0, 1)
        rep1(h, 0, 1)
        rep1(i, 0, 1)
        rep1(j, 0, 1)
        {
    
    
            int sum = 0;
            sum += a * x[0] + b * x[1] + c * x[2] + d * x[3] + e * x[4] + f * x[5] + g * x[6] + h * x[7] + i * x[8] + j * x[9];
            num[sum] = 1;//可以枚举到的标记一下
        }
        rep1(i, 1, 10000)//输出没枚举过的最小的
        if (num[i] == 0)
        {
    
    
            printf("%d\n", i - 1);
            break;
        }
    }
    return 0;
}
//这里因为n最大为10所以好写,但如果n为更大的呢,明显不合适,下面就是dfs的写法

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

思路2:dfs
我们需要递归来帮我们明确每一个球应该做的哪个选择,但要有递归出口
//dfs写法1:枚举01
#include <stack>
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <cmath>
#include <unordered_map>
#define rep1(i, a, n) for (int i = a; i <= n; i++)
#define rep2(i, a, n) for (int i = a; i >= n; i--)
#define mm(a, b) memset(a, b, sizeof(a))
#define elif else if
typedef long long ll;
const int int_max = 1 << 31 - 1;
using namespace std;
int a[15],flag[15];
int cnt[10010];
void dfs(int i,int n)
{
    
    
    if(i>n) //递归出口
    {
    
    
        int sum=0;
        rep1(o,1,n)
            if(flag[o]) sum+=a[o];
        cnt[sum]++;//能构成的记录一下
        return ;
    }
    //下面的是帮我们枚举第i个球是否要选
    flag[i]=0;
    dfs(i+1,n);
    flag[i]=1;
    dfs(i+1,n);
}
int main()
{
    
    
    int T;
    cin>>T;
    while(T--)
    {
    
    
        mm(cnt, 0);
        mm(a, 0);
        mm(flag, 0);
        int n;
        cin>>n;
        rep1(i,1,n) 
            cin>>a[i];
        dfs(1,n);
        rep1(i,1,10000)
            if(!cnt[i])
            {
    
    
                cout << i - 1 << endl;
                break;
            }
    }
}
//dfs写法2:边递归边记录sum
#include <stack>
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <cmath>
#include <unordered_map>
#define rep1(i, a, n) for (int i = a; i <= n; i++)
#define rep2(i, a, n) for (int i = a; i >= n; i--)
#define mm(a, b) memset(a, b, sizeof(a))
#define elif else if
typedef long long ll;
const int int_max = 1 << 31 - 1;
using namespace std;
int a[15];
int cnt[10010];
void dfs(int i,int n,int sum)
{
    
    
    if(i>n) //递归出口
    {
    
    
        cnt[sum]++;//能构成的记录一下
        return ;
    }
    //下面的是帮我们枚举第i个球是否要选
    dfs(i+1,n,sum);//不加a[i]
    dfs(i+1,n,sum+a[i]);//加a[i]
}
int main()
{
    
    
    int T;
    cin>>T;
    while(T--)
    {
    
    
        mm(cnt, 0);
        mm(a, 0);
        int n;
        cin>>n;
        rep1(i,1,n) 
            cin>>a[i];
        dfs(1,n,0);
        int min1 = int_max;
        rep1(i,1,10000)
            if(!cnt[i])
            {
    
    
                cout << i - 1 << endl;
                break;
            }
    }
}

简单DFS

回家

洛谷测试链接

题目描述
小H在一个划分成了n*m个方格的长方形封锁线上。 每次他能向上下左右四个方向移动一格(当然小H不可以静止不动), 但不能离开封锁线,否则就被打死了。 刚开始时他有满血6点,每移动一格他要消耗1点血量。一旦小H的 血量降到 0, 他将死去。 他可以沿路通过拾取鼠标(什么鬼。。。)来补满血量。只要他走到有鼠标的格子,他不需要任何时间即可拾取。格子上的鼠标可以瞬间补满,所以每次经过这个格子都有鼠标。就算到了某个有鼠标的格子才死去, 他也不能通过拾取鼠标补满 HP。 即使在家门口死去, 他也不能算完成任务回到家中。
地图上有 5 种格子:
数字 0: 障碍物。
数字 1: 空地, 小H可以自由行走。
数字 2: 小H出发点, 也是一片空地。
数字 3: 小H的家。
数字 4: 有鼠标在上面的空地。
小H能否安全回家?如果能, 最短需要多长时间呢?

输入描述:
第一行两个整数n,m, 表示地图的大小为n*m。
下面 n 行, 每行 m 个数字来描述地图。

输出描述:
一行, 若小H不能回家, 输出-1,否则输出他回家所需最短时间。

样例
输入
3 3
2 1 1
1 1 0
1 1 3
输出
4

说明/提示
1<=n,m<=9

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

思路:
一道dfs的水题,注意死亡情况分析(读懂吃血包)和剪枝步数就能过
#include <stack>
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <cmath>
//#include <unordered_map>
//#define rep1(i, a, n) for (int i = a; i <= n; i++)
//#define rep2(i, a, n) for (int i = a; i >= n; i--)
//#define mm(a, b) memset(a, b, sizeof(a))
//#define elif else if
typedef long long ll;
const int INF = 0x7FFFFFFF;
using namespace std;
int dx[4] = {
    
    0, 0, 1, -1};
int dy[4] = {
    
    1, -1, 0, 0};//枚举走向
int n, m;
int map[11][11];
int startX, startY;//记录起点
int minTime=INF;
void dfs(int x,int y,int step,int HP)//x表示第x行,y表示第y列,step记录走的步数,hp记录血量
{
    
    
    if(x>n||x<1||y>m||y<1||HP==0)//小H的死亡边界(递归出口)
        return;
    if(step>=minTime||step>n*m)//*剪枝:删去比之前算的最小时间大的与超过步数上界的(递归出口)
        return;
    if(map[x][y]==3)//小H的回家边界(递归出口)
    {
    
    
        minTime = min(minTime, step);
        return;
    }
    if(map[x][y]==4)//补血站
        HP = 6;
    
    for(int i=0;i<4;i++)//进入递归
    {
    
    
        if(map[x+dx[i]][y+dy[i]])//是1就移动
            dfs(x + dx[i], y + dy[i], step + 1, HP - 1);
    }
}
int main()
{
    
    
    cin >> n >> m;
    memset(map, 0, sizeof(map));
    for (int i = 1; i <= n;i++)
        for (int j = 1; j <= m;j++)
        {
    
    
            cin >> map[i][j];//打印地图
            if (map[i][j] == 2)
                startX = i, startY = j;//记录出发点
        }
    dfs(startX, startY, 0, 6);
    if(minTime!=INF)
        cout << minTime;
    else
        cout << "-1";
    return 0;
}

皇后棋盘问题

洛谷测试链接

题目描述:
一个如下的6×6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。
在这里插入图片描述
上面的布局可以用序列2 4 6 1 3 5 来描述,第i个数字表示在第i行的相应位置有一个棋子,如下:
行号 1 2 3 4 5 6
列号 2 4 6 1 3 5
这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前3个解。最后一行是解的总个数。

输入格式
一行一个正整数 nn,表示棋盘是n×n 大小的。
6≤n≤13

输出格式
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

样例
输入
6
输出
2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

思路:
1.建立记录两个对角线、行、列的数组
2.拿记录行的数组枚举记录,拿另外三个剪枝
#include <stack>
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <cmath>
typedef long long ll;
const int INF = 0x7FFFFFFF;
using namespace std;

//***难点为记录数组能否想到
int a[50]; //存行
int b[50]; //存列
int c[50]; //存右上到左下
int d[50]; //存左上到右下
int n;//棋盘大小
int cnt = 0;//输出个数

void dfs(int i) //i表行,j表列
{
    
    
    for (int j = 1; j <= n; j++)
    {
    
    
        if (b[j] || c[i + j] || d[i + n - j])//可行性剪枝,标记过的取消
            continue;
        
        //标记当前结点
        a[i] = j;
        b[j] = 1;//列被占
        c[i + j] = 1;//右上到左下为和相等
        d[i + n - j] = 1;//左上到右下为差相等
        
        if (i == n)
        {
    
    
            cnt++;
            if (cnt <= 3)
            {
    
    
                for (int i = 1; i <= n; i++)
                    i == 1 ? cout << a[i] : cout << " " << a[i];
                cout << endl;
            }
        }
        
        dfs(i + 1);
        b[j] = 0, c[i + j] = 0, d[i + n - j] = 0;//回溯
    }
}

int main()
{
    
    
    cin >> n;
    dfs(1);
    cout << cnt;
    return 0;
}

油田----dfs查找连通块

POJ测试链接
这是一道很经典的dfs题,很多平台都是直接导向的UVA,半天提交不上,终于在POJ找到了用自己的判断姬判这题的…

题目描述:
输入多个m行n列的矩阵,用00表示输入结束。找出有多少块石油区域,用“@”代表石油,假如两个“@”在横,竖或对角线上相邻,就说它们位于同一区域,对于每个输入,输出一个数表示有几个石油区域。

样例
在这里插入图片描述
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

思路:
1.dfs内遍历'@',并不断改成'*',将这个连通区域内的都换掉
2.每dfs一次,cnt++
#include <stack>
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <cmath>
#include <unordered_map>
#define rep1(i, a, n) for (int i = a; i <= n; i++)
#define rep2(i, a, n) for (int i = a; i >= n; i--)
#define mm(a, b) memset(a, b, sizeof(a))
#define elif else if
typedef long long ll;
const int INF = 0x7FFFFFFF;
using namespace std;
int m, n; //m行n列
char map[105][105];//绘制地图
int cnt = 0;//记录有多少个连通区域

int dx[8] = {
    
    0, 0, 1, -1, 1, -1, 1, -1};//八个方向的移动
int dy[8] = {
    
    1, -1, 0, 0, 1, 1, -1, -1};

void dfs(int x, int y)
{
    
    
    if (x >= m || x < 0 || y >= n || y < 0)//边界全图
        return;
    if (map[x][y] == '*')//连通区域边界
        return;

    map[x][y] = '*';//换掉
    rep1(i,0,7)
        dfs(x + dx[i], y + dy[i]);//八个方向搜索
}

int main()
{
    
    
    while (cin >> m >> n, m != 0 || n != 0)
    {
    
    
        cnt = 0;
        getchar();
        rep1(i,0,m-1)//打印地图
            scanf("%s", map[i]);
        
        rep1(i,0,m-1)
            rep1(j,0,n-1)
                if (map[i][j] == '@')//遇到就开始dfs
                    dfs(i, j), cnt++;
        
        cout << cnt << endl;
    }
    return 0;
}

全排列

全排列是测试是否明白某种搜索的有效题,自己写,少用next_permutation()

洛谷测试链接

题目描述
输出自然数 1 到 n 所有不重复的排列,即 n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

输入格式
一个整数 n (1<=n<=9)

输出格式
由1∼n组成的所有不重复的数字序列,每行一个序列。
每个数字保留5个场宽。

样例
输入
3
输出
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

//如果拿next_permutation写就是一道水题
//可以拿dfs写思考如何构建输出
dfs思路:
1.构建一个全排列输出顺序的数组
2.构建一个固定排列中记录是否存在某数的数组
#include <stack>
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <cmath>
#include <cstdio>
//#include <unordered_map>
//#define rep1(i, a, n) for (int i = a; i <= n; i++)
//#define rep2(i, a, n) for (int i = a; i >= n; i--)
//#define mm(a, b) memset(a, b, sizeof(a))
//#define elif else if
typedef long long ll;
const int INF = 0x7FFFFFFF;
using namespace std;
int n;
int vis[20];//记录在该排列中某数是否使用过
int num[20];//记录输出顺序
void dfs(int i)
{
    
    
    if(i>n)//dfs边界,输出
    {
    
    
        for (int j = 1; j <= n;j++)
            printf("%5d", num[j]);
        cout << endl;
        return;
    }

    for (int j = 1; j <= n;j++)
    {
    
    
        if(!vis[j])//防止重复
        {
    
    
            vis[j] = 1;//记录存在
            num[i] = j;//记录顺序
            dfs(i + 1);
            //下面为回溯
            vis[j] = 0;
            num[i] = 0;
        }
    }
}
int main()
{
    
    
    cin >> n;
    dfs(1);
    return 0;
}

定时出口

HDU测试链接

题目描述
有人被困在了一个N*M的地图中,门之前是关闭的,只有一个特殊的时间T能打开,有墙阻挡他移动,且不能在两次走入同一个地方,他是否能逃出迷宫?

输入描述
输入由多个测试用例组成。
每个测试用例的第一行包含三个整数N,M和T(1 < N,M < 7; 0 < T <50),分别表示迷宫的大小和门打开的时间。
接下来的N行给出迷宫布局,每行包含M个字符。
每个字符含义如下:
‘X’:不能进入的墙
‘S’:起点
‘D’:门
‘.’:可以行走的地方
输入以三个0结束,这个测试用例不被处理。

输出描述
对于每组测试数据,如果他能够逃出迷宫,输出YES,否则输出NO,每组测试数据占一行

样例
输入:
4 4 5
S.X.
…X.
…XD

3 4 5
S.X.
…X.
…D
0 0 0
输出:
NO
YES
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

思路:
正常的走图,但记着剪枝就行否则TLE

奇偶剪枝:

1 2 3
4 5 6
在这种情况下,从1到4最少有一步,其次可以1->2->5->4加了两步,也有1->2->3->6->5->4加了四步,但都是偶数步,所以可以将相差奇数步的都取消来做剪枝
#include <stack>
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <cmath>
#include <cstdio>
#define rep1(i, a, n) for (int i = a; i <= n; i++)
#define rep2(i, a, n) for (int i = a; i >= n; i--)
#define mm(a, b) memset(a, b, sizeof(a))
#define elif else if
typedef long long ll;
const int INF = 0x7FFFFFFF;
using namespace std;
typedef long long ll;
int sX, sY;
int eX, eY;
int N, M, T;
char map[11][11];
int vis[11][11]; //没走为0
int dx[4] = {
    
    0, 0, -1, 1};
int dy[4] = {
    
    1, -1, 0, 0};
bool flag;

void dfs(int x, int y, int TT)
{
    
    
    if (TT > T || flag == true)//剪枝:判断有没有成立条件了与是否超时了
        return;

    int temp = T - TT - (abs(x - eX) + abs(y - eY));//奇偶剪枝:若剩余最小步数与剩余时间之差为奇数无法做到
    if(temp&1||temp<0)
        return;

    if (map[x][y] == 'D' && TT == T)
    {
    
    
        flag = true;
        return;
    }

    rep1(i, 0, 3)
    {
    
    
        if(map[x+dx[i]][y+dy[i]]=='X'||x+dx[i]<0||x+dx[i]>=N||y+dy[i]<0||y+dy[i]>=M)//判边界
            continue;
        if (vis[x + dx[i]][y + dy[i]])//判是否走过了
            continue;
        vis[x + dx[i]][y + dy[i]] = 1;
        dfs(x + dx[i], y + dy[i], TT + 1);
        vis[x + dx[i]][y + dy[i]] = 0;
    }
}
int main()
{
    
    
    while (scanf("%d%d%d", &N, &M, &T) != EOF)
    {
    
    
        if (N == 0 && M == 0 && T == 0)
            break;
        getchar();
        rep1(i, 0, 10) rep1(j, 0, 10) vis[i][j] = 0;

        flag = false;

        rep1(i, 0, N - 1)
        {
    
    
            for (int j = 0; j < M; j++)
            {
    
    
                scanf("%1c", &map[i][j]);
                if (map[i][j] == 'S')
                {
    
    
                    sX = i, sY = j;
                    vis[i][j] = 1;
                }
                else if(map[i][j]=='D')
                    eX = i, eY = j;
            }
            getchar();
        }

        dfs(sX, sY, 0);

        if (flag == false)
            printf("NO\n");
        else
            printf("YES\n");
    }
    return 0;
}


思维深搜题

相似字符串组

LeetCode测试链接

题目描述:
如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等,那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。
例如,“tars” 和 “rats” 是相似的 (交换 0 与 2 的位置); “rats” 和 “arts” 也是相似的,但是 “star” 不与 “tars”,“rats”,或 “arts” 相似。
总之,它们通过相似性形成了两个关联组:{“tars”, “rats”, “arts”} 和 {“star”}。注意,“tars” 和 “arts” 是在同一组中,即使它们并不相似。形式上,对每个组而言,要确定一个单词在组中,只需要这个词和该组中至少一个单词相似。
给你一个字符串列表 strs。列表中的每个字符串都是 strs 中其它所有字符串的一个字母异位词。请问 strs 中有多少个相似字符串组?

样例:
输入:strs = [“tars”,“rats”,“arts”,“star”]
输出:2

输入:strs = [“omv”,“ovm”]
输出:1

提示:
1 <= strs.length <= 300
1 <= strs[i].length <= 300
strs[i] 只包含小写字母。
strs 中的所有单词都具有相同的长度,且是彼此的字母异位词。
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

//从题的描述很容易看出来可以用连通或者并查集做
//只要能想到连通做法,注意一下判断相似的细节,基本上还是能一次ac的
思路:
1.先设立判断两字符串是否相似的函数
2.做dfs遍历连通区
3.main函数内判断要遍历几个连通区
class Solution {
    
    

    map<string,int> vis;//标记某字符串是否被拉进一个连通区内

    bool flagSame(string x,string y)//判断两字符串是否相似
    {
    
    
        if(x.size()!=y.size()) return false;

        int cnt=0;//计算两字符串有几个差别,先广义判断一下筛出有两个差别的
        for(int i=0;i<x.size();i++)  if(x[i]!=y[i]) cnt++;
        if(cnt!=0&&cnt!=2) return false;
        else if(cnt==0) return true;

        int firstX,lastX;//精准判断,x字符串将两个差别位置换一下和y一样不一样
        for(int i=0;i<x.size();i++)     if(x[i]!=y[i])   {
    
    firstX=i;break;}
        for(int i=x.size()-1;i>=0;i--)  if(x[i]!=y[i])   {
    
    lastX=i;break;}
        swap(x[firstX],x[lastX]);
        if(x!=y) return false;
        return true;
    }

    void dfs(vector<string> strs,int cur)//深搜连通区,将能归为一个连通组的标记为1,cur为派出来的拉别的字符串进组的小兵(子结点)
    {
    
    
        for(int i=0;i<strs.size();i++)
        {
    
    
            if(!vis[strs[i]]&&flagSame(strs[i],strs[cur])) //所有相似的进组
                vis[strs[i]]=1,dfs(strs,i);
        }
        return;
    }
public:
    int numSimilarGroups(vector<string>& strs) {
    
    
        if(strs.size()==0) return 0;
        
        int sum=0;//记录开过几个连通组
        for(int i=0;i<strs.size();i++)
        {
    
    
            if(!vis[strs[i]]) //每找到一个没有被标记过的开一次连通组
            {
    
    
                dfs(strs,i),sum++;
            }
        }
        return sum;
    }
};

猜你喜欢

转载自blog.csdn.net/SnopzYz/article/details/113568379