SDNU-ACM-ICPC 2020 DFS&BFS (咕咕o(≧v≦)o)

传送门

Red and Black

题意:

m * n的地图,#不可以走,.可以走,@是起点,问你从@开始能走到的点的个数是多少

方法1:dfs

这个题相当于问的是从起点开始能走到的位置,跟路径没有关系,只要dfs整个地图就可以,而且每个点只需要走一遍,我们就判断如果是‘.’并且没被标记过,就更新答案,然后标记一下

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 7
#define endl '
'
#define mod 1e9+7;
typedef  long long ll ;
//不开longlong见祖宗!
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);

inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;
        ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

int n, m, xx, yy, ans;
char tr[25][25];
int dx[] = {1, 0, -1, 0};
int dy[] = {0, -1, 0, 1};
bool vis[25][25];

void dfs(int x, int y){
    if(tr[x][y] == '.' && vis[x][y] == 0){
        ans++;
        vis[x][y] = 1;
    }
    else return;
    for(int i = 0; i < 4; ++i){
        xx = x + dx[i];
        yy = y + dy[i];
        dfs(xx, yy);
    }
}

int main(){
    while(cin>>n>>m && n != 0 && m != 0){
        memset(tr, 0, sizeof(tr));
        memset(vis, 0, sizeof(vis));
        ans = 0;
        swap(n, m);//本题是m行n列,将其转化成n行m列会好写点
        for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j){
        scanf(" %c",&tr[i][j]);
            if(tr[i][j] == '@'){
                xx = i; yy = j;
                tr[i][j] = '.';
            }
        }
        dfs(xx, yy);
        cout<<ans<<endl;
    }
    return 0;
}

方法2:bfs

因为每个点只走一遍,就很符合bfs的特点

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 7
#define endl '
'
#define mod 1e9+7;
typedef  long long ll ;
//不开longlong见祖宗!
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);

inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;
        ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

int n, m, xx, yy, ans;
char tr[25][25];
int dx[] = {1, 0, -1, 0};
int dy[] = {0, -1, 0, 1};
bool vis[25][25];
struct ran{
    int x, y;
};
queue<ran>q;
bool judge(int x, int y){
    if(x > n || x < 1 || y > m || y < 1)return false;
    else if(vis[x][y])return false;
    else if(tr[x][y] == '#')return false;
    else return true;
}

void bfs(){
    ran now, next;
    now.x = xx; now.y = yy;
    q.push(now);
    vis[now.x][now.y] = 1;
    while (!q.empty()) {
        now = q.front();q.pop();
        if(tr[now.x][now.y] == '.'){
            ans++;
        }
        for(int i = 0; i < 4; ++i){
            next.x = now.x + dx[i];
            next.y = now.y + dy[i];
            if(!judge(next.x, next.y))continue;
            vis[next.x][next.y] = 1;
            q.push(next);
        }
        
    }
}

int main(){
    while(cin>>n>>m && n != 0 && m != 0){
        memset(tr, 0, sizeof(tr));
        memset(vis, 0, sizeof(vis));
        ans = 0;
        swap(n, m);
        for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j){
        scanf(" %c",&tr[i][j]);
            if(tr[i][j] == '@'){
                xx = i; yy = j;
                tr[i][j] = '.';
                vis[i][j] = 1;
            }
        }
        bfs();
        cout<<ans<<endl;
    }
    return 0;
}

B - 棋盘问题

题意:

在给定棋盘上放棋子,其中#位置不能放,且你放的所有的棋子中的任意两个,不能在同一行或同一列,问你总共有多少种摆法

思路:

这个题只能dfs,按行搜,

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 7
#define endl '
'
#define mod 1e9+7;
typedef  long long ll ;
//不开longlong见祖宗!
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);

inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;
        ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

int n, k, xx, yy, ans, step;
bool vis[10];
char tr[10][10];
bool judge(int x, int y){
    if(x > n || x < 1 || y > n || y < 1)return false;
    else if(tr[x][y] == '#')return false;
    else return true;
}
void dfs(int x){
    if(step == k){
        ans++;
        return;
    }
    if(x > n)return;//这个和下面的那个是配对的,当你一直跳到下一行就可以会跳出去了
    for(int y = 1; y <= n; ++y){
        if(judge(x, y))continue;
        if(vis[y])continue;
        vis[y] = 1;
        step++;
        dfs(x + 1);
        step--;
        vis[y] = 0;
    }
    dfs(x + 1);//可能这个行没有点可以用,就得手动跳到下一行
}

int main(){
    while (cin>>n>>k && n != -1 && k != -1) {
        memset(tr, 0, sizeof(tr));
        memset(vis, 0, sizeof(vis));
        ans = 0;
        for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= n; ++j)
        scanf(" %c",&tr[i][j]);
        dfs(1);
        cout<<ans<<endl;
    }
}

C - Dungeon Master

题意:

三维迷宫,问你能不能从S走到E,只能上下左右前后走,而且不能走#格

思路:

bfs就完事了,输入的是一层一层的,所以对于xyz会有点奇怪

一定一定一定一定一定要记得给他么的狗队列清0 ,不然会wa的很惨(只有亲身经历后才知道有多崩溃!呜呜呜)

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 7
#define endl '
'
#define mod 1e9+7;
typedef  long long ll ;
//不开longlong见祖宗!
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);

inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;
        ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

int h, n, m, xx, yy, zz, ans;//h是高度,n是行数,m是列数
char tr[35][35][35];
bool vis[35][35][35];
int dx[] = {1, 0, -1, 0, 0, 0};
int dy[] = {0, 1, 0, -1, 0, 0};
int dz[] = {0, 0, 0, 0, 1, -1};
bool judge(int z, int x, int y){
    if(z > h || z < 1 || x > n || x < 1 || y > m || y < 1)return false;
    else if(vis[z][x][y])return false;
    else if(tr[z][x][y] == '#')return false;
    else return true;
}
struct ran{
    int x, y, z, step;
};
queue<ran>q;//千万千万要给队列初始化!

int  bfs(){
    ran now, next;
    now.z = zz;now.x = xx;now.y = yy;now.step = 0;
    q.push(now);
    vis[now.z][now.x][now.y] = 1;
    while (!q.empty()) {
        now = q.front();
        q.pop();
        if(tr[now.z][now.x][now.y] == 'E'){
            return now.step;
        }
        for(int i = 0; i < 6; ++i){
            next.z = now.z + dz[i];
            next.x = now.x + dx[i];
            next.y = now.y + dy[i];
            if(!judge(next.z, next.x, next.y))continue;
            vis[next.z][next.x][next.y] = 1;
            next.step = now.step + 1;
            q.push(next);
        }
    }
    return 0;
}

int main(){
    while (cin>>h>>n>>m && (h + n + m)) {
        memset(tr, 0, sizeof(tr));
        memset(vis, 0, sizeof(vis));
        while (!q.empty()) {//千万要给队列初始化!
            q.pop();
        }
        ans = 0;
        for(int i = 1; i <= h; ++i)
        for(int j = 1; j <= n; ++j){
        scanf(" %s",tr[i][j] + 1);
        for(int k = 1; k <= m; ++k){
            if(tr[i][j][k] == 'S'){
                zz = i;xx = j;yy = k;
                tr[i][j][k] = '.';
            }
        }
        }
        ans = bfs();
        if(ans)
            printf("Escaped in %d minute(s).
",ans);
        else
            printf("Trapped!
");
    }
    return 0;
}

D - Catch That Cow

题意:

在0到1e5的道路上,农夫要去抓牛,牛不动,农夫可以在一分钟内可以向前移动一格或者向后移动一个,或者到达2倍位置的地方,问最短多长时间抓到牛

思路:

一维bfs,注意不能走重复,因为如果重复了就代表这绝对不是最短距离

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 7
#define endl '
'
#define mod 1e9+7;
typedef  long long ll ;
//不开longlong见祖宗!
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);

inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;
        ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

int n, k;
bool vis[MAX];
struct ran{
    int x, step;
};
queue<ran>q;

bool judge(int x){
    if(x > 1000001 || x < 0)return false;
    else if(vis[x])return false;
    else return true;
}

int bfs(){
    ran now, next;
    now.x = n;now.step = 0;
    q.push(now);
    vis[now.x] = 1;
    while (!q.empty()) {
        now = q.front();q.pop();
        if(now.x == k){
            return now.step;
        }
        next.x = now.x * 2;next.step = now.step + 1;
        if(judge(next.x)){
            q.push(next);
            vis[next.x] = 1;
        }
            
        next.x = now.x - 1; next.step = now.step + 1;
        if(judge(next.x)){
            q.push(next);
            vis[next.x] = 1;
        }
        next.x = now.x + 1; next.step = now.step + 1;
        if(judge(next.x)){
            q.push(next);
            vis[next.x] = 1;
        }
    }
    return 0;
}

int main(){
    cin>>n>>k;
    cout<<bfs()<<endl;
}

G - 胜利大逃亡

题意:

三维地图,问你能不能在规定时间内从(1,1,1)走到(h, n, m)

思路:

三维bfs即可,同样的xyz的顺序不是那么顺

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 7
#define endl '
'
#define mod 1e9+7;
typedef  long long ll ;
//不开longlong见祖宗!
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);

inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;
        ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

int T, n, m, h, t;
int tr[55][55][55];
bool vis[55][55][55];
int dx[] = {1, 0, -1, 0, 0, 0};
int dy[] = {0, 1, 0, -1, 0, 0};
int dz[] = {0, 0, 0, 0, 1, -1};
struct ran{
    int x, y, z, step;
};
queue<ran>q;
bool judge(int z, int x, int y){
    if(z > h || z < 1 || x > n || x < 1 || y > m || y < 1)return false;
    else if(vis[z][x][y])return false;
    else if(tr[z][x][y] == 1)return false;
    else return true;
}

void init(){//初始化
    memset(tr, 0, sizeof(tr));
    memset(vis, 0, sizeof(vis));
    while (!q.empty()) {
        q.pop();
    }
}

int bfs(){
    ran now, next;
    now.x = 1;now.y = 1;now.z = 1;now.step = 0;
    q.push(now);
    vis[1][1][1] = 1;
    while (!q.empty()) {
        now = q.front();q.pop();
        if(now.z == h && now.x == n && now.y == m){
            return now.step;
        }
        for(int i = 0; i < 6; ++i){
            next.z = now.z + dz[i];next.x = now.x + dx[i];next.y = now.y + dy[i];
            if(!judge(next.z, next.x, next.y))continue;
            vis[next.z][next.x][next.y] = 1;
            next.step = now.step + 1;
            q.push(next);
            }
    }
    return 0;
}

int main(){
    cin>>T;
    while (T--) {
        init();
        cin>>h>>n>>m>>t;
        for(int i = 1; i <= h; ++i)
        for(int j = 1; j <= n; ++j)
        for(int k = 1; k <= m; ++k)
        tr[i][j][k] = IntRead();
        int ans = bfs();
        if(ans != 0 && ans <= t)cout<<ans<<endl;
        else cout<<-1<<endl;
        
    }
}

H - A计划

题意:

在三维图内救公主,从(0,0,0)出发,不能走*,遇到#就会传送到另一层的同一个位置,如果传送过去的地方是#就会直接撞死,问你能不能在t时刻找到公主

思路:

bfs,遇到传送门就得特判,另一层的同一个位置不可以是*或#

这个题说的是能不能在t时刻找到公主,但ac码是能不能在t时刻之前找到,我就有点懵o(︶︿︶)o

还有就是最后输出的是YES和NO,而不是最短时间!靠

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 7
#define endl '
'
#define mod 1e9+7;
typedef  long long ll ;
//不开longlong见祖宗!
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);

inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;
        ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

int T, n, m, h, t, xx, yy, zz;
char tr[5][55][55];
bool vis[5][55][55];
int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};
struct ran{
    int x, y, z, step;
};
queue<ran>q;

bool judge(int z, int x, int y){
    if(x > n || x < 1 || y > m || y < 1 || z < 1 || z > 2)return false;
    else if(vis[z][x][y])return false;
    else if(tr[z][x][y] == '*')return false;
    else return true;
}

void init(){
    memset(tr, 0, sizeof(tr));
    memset(vis, 0, sizeof(vis));
    while (!q.empty()) {
        q.pop();
    }
}

int bfs(){
    ran now, next;
    now.z = zz;now.x = xx;now.y = yy;now.step = 0;
    q.push(now);vis[zz][xx][yy] = 1;
    while (!q.empty()) {
        now = q.front();q.pop();
        if(tr[now.z][now.x][now.y] == 'P'){
            return now.step;
        }
        for(int i = 0; i < 4; ++i){
            next.z = now.z;next.x = now.x + dx[i];next.y = now.y + dy[i];
            if(tr[next.z][next.x][next.y] == '#'){
                if(next.z == 1)next.z++;
                else if(next.z == 2)next.z--;
                if(tr[next.z][next.x][next.y] == '#')continue;
                if(!judge(next.z, next.x, next.y))continue;
                vis[next.z][next.x][next.y] = 1;
                next.step = now.step + 1;
                q.push(next);
            }
            else {
                if(!judge(next.z, next.x, next.y))continue;
                vis[next.z][next.x][next.y] = 1;
                next.step = now.step + 1;
                q.push(next);
            }
        }
    }
    return 0;
}


int main(){
    cin>>T;
    while (T--) {
        init();
        cin>>n>>m>>t;
        //cout<<n<<m<<t;
        for(int i = 1; i <= 2; ++i)
        for(int j = 1; j <= n; ++j)
        for(int k = 1; k <= m; ++k){
            scanf(" %c",&tr[i][j][k]);
            if(tr[i][j][k] == 'S'){
                zz = i;xx = j; yy = k;
            }
        }
        int ans = bfs();
        if(ans != 0 && ans <= t)
            cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
        
    }
    return 0;
}

I - Sum It Up

题意:

m个数,从中找任意多个数,要保证其和等于n,且不重复的情况的个数,并降序输出每种情况,每种情况也是降序输出

思路:

首先因为要降序输出,所以得对数列进行降序排列,然后通过dfs进行搜索,两个变量:star表示走到了哪个位置,sum表示到目前为止的和

最重要的其实是去重,这里通过star来控制就能实现,同时对于每次return后要去掉这之后所有与他相同的数字

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 7
#define endl '
'
#define mod 1e9+7;
typedef  long long ll ;
//不开longlong见祖宗!
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);

inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;
        ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

int n, m, num, ans;
int tr[100], ar[100];
bool vis[100];

void init(){
    memset(tr, 0, sizeof(tr));
    memset(vis, 0, sizeof(vis));
    memset(ar, 0, sizeof(ar));
    ans = 0;num = 0;
}
 
bool cmp(int x, int y){
    return x > y;
}

void dfs(int star, int sum){
    if(sum > n)return;
    else if(sum == n){
        ans = 1;
        for(int i = 1; i <= num; ++i){
            if(i != num)cout<<ar[i]<<'+';
            else cout<<ar[i]<<endl;
        }
    }
    for(int i = star; i <= m; ++i){
        ar[++num] = tr[i];
        vis[i] = 1;
        dfs(i + 1, sum + tr[i]);
        vis[i] = 0;
        num--;
        while (i + 1 <= m && tr[i] == tr[i + 1]) {
            i++;
        }
    }
}

int main(){
    while (cin>>n>>m && (n + m)) {
        init();
        for(int i = 1; i <= m; ++i)cin>>tr[i];
        sort(tr + 1, tr + 1 + m, cmp);
        printf("Sums of %d:
",n);
        dfs(1, 0);
        if(!ans)cout<<"NONE
";
    }
}

J - N皇后问题

思路:

两个皇后不能在行或列或对角线上,对角线有两个,我们还是同B题一样按行搜,对每行的列进行dfs,这次vis数组要开二维的,好记录列与两个对角线是否标记过,对于对角线相当于一个一次函数,而我们标记的是他的y = kx + b中的b,k = 1或-1,b就等于x + y或 x - y,但是x - y可能会出现负数,所以我们可以加上n,这样就可以保证下标大于0,但是要给数组开的稍微大一点点,这个数n + x - y最大是20,超过20就可以(我第一遍开了个15,就直接wa了,艹),再就是要注意用数组存答案,然后人家问什么就直接输出

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 7
#define endl '
'
#define mod 1e9+7;
typedef  long long ll ;
//不开longlong见祖宗!
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);

inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;
        ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

int n, tr[15];
bool vis[3][100];
void init(){
    memset(vis, 0, sizeof(vis));
    
}

bool judge(int x, int y){
    if(vis[0][y])return false;
    else if(vis[1][x + y])return false;
    else if(vis[2][n + x - y])return false;
    else return true;
}

void dfs(int x){
    if(x == n){
        tr[n]++;
        return;
    }
    for(int y = 1; y <= n; ++y){
        if(!judge(x, y))continue;
        vis[0][y] = 1;
        vis[1][x + y] = 1;
        vis[2][n + x - y] = 1;
        dfs(x + 1);
        vis[0][y] = 0;
        vis[1][x + y] = 0;
        vis[2][n + x - y] = 0;
    }
}

int main(){
    for(int i = 1; i <= 10; ++i){
        n = i;
        init();
        dfs(0);
    }
    while (cin>>n && n) {
        cout<<tr[n]<<endl;
    }
}

K - Oil Deposits

题意:

给你一个地图,@代表油田,其他点代表石头,问你总共有几个油田,其中一个点可以和周围八个点相连

思路1:

dfs:直接怼暴力,搜整个图,遇到一个@且未经过标记的就开始dfs,dfs的时候要对所有相连的@进行标记,最好输出ans即可

注意,这次dfs要在刚开始就标记,因为如果写在循环判断后面,就可能你搜 的点是@但周围八个点全是石头,就不会更新答案滴

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 7
#define endl '
'
#define mod 1e9+7;
typedef  long long ll ;
//不开longlong见祖宗!
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);

inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;
        ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

char tr[105][105];
bool vis[105][105];
int n, m, ans, cnt;
int dx[] = {1, 0, -1, 0, -1, 1, 1, -1};
int dy[] = {0, 1, 0, -1, -1, 1, -1, 1};


void init(){
    memset(vis, 0, sizeof(vis));
    memset(tr, 0, sizeof(tr));
    ans = 0;
}

bool judge(int x, int y){
    if(x > n || x < 1 || y > m || y < 1)return false;
    else if(vis[x][y])return false;
    else if(tr[x][y] == '*')return false;
    else return true;
}

void dfs(int x, int y){
    if(tr[x][y] == '@'){
        cnt = 1;
        vis[x][y] = 1;
    }
    for(int i = 0; i < 8; ++i){
        int xx = x + dx[i];
        int yy = y + dy[i];
        if(!judge(xx, yy))continue;
        //vis[xx][yy] = 1;
        //cnt = 1;
        dfs(xx, yy);
        //vis[xx][yy] = 0;
    }
}

int main(){
    while (cin>>n>>m && (n + m)) {
        init();
        for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j)
        scanf(" %c", &tr[i][j]);
        for(int i = 1; i <= n; ++i)//直接暴力搜图
        for(int j = 1; j <= m; ++j){
            if(!vis[i][j] && tr[i][j] == '@'){
                cnt = 0;
                dfs(i, j);
                if(cnt)ans++;
            }
        }
        cout<<ans<<endl;
    }
  	return 0;
}

思路2:

这个题每个点只需要走一次,所以也可以用bfs,思路和dfs差不多

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 7
#define endl '
'
#define mod 1e9+7;
typedef  long long ll ;
//不开longlong见祖宗!
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);

inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;
        ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

char tr[105][105];
bool vis[105][105];
int n, m, ans, cnt;
int dx[] = {1, 0, -1, 0, -1, 1, 1, -1};
int dy[] = {0, 1, 0, -1, -1, 1, -1, 1};
struct ran{
    int x, y;
};
queue<ran>q;

void init(){//初始化
    memset(vis, 0, sizeof(vis));
    memset(tr, 0, sizeof(tr));
    ans = 0;
}

bool judge(int x, int y){//判断条件
    if(x > n || x < 1 || y > m || y < 1)return false;
    else if(vis[x][y])return false;
    else if(tr[x][y] == '*')return false;
    else return true;
}


void bfs(int x, int y){
    if(tr[x][y] == '@' && vis[x][y] == 0){//更新答案
        cnt = 1;
    }
    while (!q.empty()) {//清空队列!!!
        q.pop();
    }
    ran now, next;
    now.x = x; now.y = y;
    q.push(now);
    vis[x][y] = 1;
    while (!q.empty()) {
        now = q.front();q.pop();
        for(int i = 0; i < 8; ++i){
            next.x = now.x + dx[i];
            next.y = now.y + dy[i];
            if(!judge(next.x, next.y))continue;
            q.push(next);
            vis[next.x][next.y] = 1;
        }
    }
}

int main(){
    while (cin>>n>>m && (n + m)) {
        init();
        for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j)
        scanf(" %c",&tr[i][j]);
        for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j){
            if(!vis[i][j] && tr[i][j] == '@'){
                cnt = 0;
                bfs(i, j);
                if(cnt)ans++;
            }
        }
        cout<<ans<<endl;
    }
}

L - 变形课

题意:

给你一堆字符串,问你能不能按成语接龙的方式从b连到m

思路:

对dfs的灵活运用

这个题有不止一个b开头的,如果暴力的话就得循环找每个b开头的,再去暴力,所以我们dfs也得这样,再者我们需要用两个数组,一个存字符串开头的字符,一个存字符串最后一个字符,dfs去跑搜的字符串的位置

注意答案输出的时候还tm有个句号,艹

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 7
#define endl '
'
#define mod 1e9+7;
typedef  long long ll ;
//不开longlong见祖宗!
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);

inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;
        ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

char star[MAX], end1[MAX];
bool vis[MAX];
string s;
int n, ans;

void dfs(int k){
    if(ans == 1){//找到答案就返回
        return;
    }
    if(end1[k] == 'm'){//找到了m
        ans = 1;
        return;
    }
    for(int i = 1; i <= n; ++i){
        if(vis[i])continue;
        if(star[i] == end1[k]){//判断能不能接龙成功
            vis[i] = 1;
            dfs(i);
            vis[i] = 0;
        }
    }
}


void init(){//初始化很重要
    memset(vis, 0, sizeof(vis));
    memset(star, 0, sizeof(star));
    memset(end1, 0, sizeof(star));
    ans = 0;n = 0;
}

int main(){
    while (cin>>s) {
        if(s [0] != '0'){//判断输入的是不是0
            star[++n] = s[0];
            end1[n] = s[s.size() - 1];
        }
        else if(s[0] == '0'){//是0就开始搜索
            for(int i = 1; i <= n; ++i){
                if(star[i] == 'b'){
                    dfs(i);
                }
                if(ans == 1){//如果ans=1就直接跳出就可以了,没必要一直搜了
                    break;
                }
            }
            if(ans)cout<<"Yes.
";
            else cout<<"No.
";
            init();//搜完记得初始化,以便下次再搜
        }
    }
    return 0;
}

写在最后:

这份搜索题是20年十一月初的,一不小心鸽了四个月⁄(⁄ ⁄ ⁄ω⁄ ⁄ ⁄)⁄,深感愧疚,之前对搜索很抵触,不过上次牛客比赛遇到了个搜索题,写个dfs却wa了好多次才过,最后才发现是retuen后vis忘归0了,就感觉再不练练的话就说不过去了,现在补上了,总体来说对那种板子题还是能写的过去,不过要是换个题型就不太行了(╥﹏╥)。噢对了,还有两个英文题太懒的搞了,就没搞,请call me 小懒猪(*≧ω≦)

不是所有的牛奶都叫特仑苏,也不是所有的人都叫猪猪
原文地址:https://www.cnblogs.com/chelsea0901/p/14468019.html