鱼C论坛

 找回密码
 立即注册
查看: 1040|回复: 15

[技术交流] 连dfs都不会了

[复制链接]
发表于 2023-9-24 20:34:12 | 显示全部楼层 |阅读模式
40鱼币
本帖最后由 陈尚涵 于 2023-9-24 20:39 编辑

草泥马,小丑了,我甜蜜的没写vis,我是该笑还是哭啊
---------------------------------------------------------------------------------------------------

https://www.luogu.com.cn/problem/P4554
这道题,我只能想到dfs
不过这不是最重要的,最重要的是我的dfs给死循环了  
找半天硬是没有发现问题,我真是越来越菜了,已经是dfs都写不好的fw了
另外说的是,这道题我没有看题解,也不打算看题解,我认为dfs应该可以做(至少能拿点分),所以只讨论关于这个代码中dfs的内容
希望大佬帮帮我
@zhangjinxuan @tommyyu @liuhongrun2022 @Wei-Yuanzhe
#include <iostream>
using namespace std;
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
int map[505][505];
int n, m, sx, sy, ex, ey, ans;
void dfs(int x, int y, int v){
        for (int i = 0; i < 4; i++){
                int xx = x + dx[i];
                int yy = y + dy[i];
                if (xx >= 0 && xx < n && yy >= 0 && yy < m); else continue;
                int vv = v;
                if (map[xx][yy] != map[x][y]) vv++;
                if (xx == ex && yy == ey){ if (vv < ans) ans = vv; else continue; }
                else dfs(xx, yy, vv);
        }
}
int main(){
        while (true){
                cin >> n >> m;
                if (n == 0 && m == 0){
                        return 0;
                }
                for (int i = 0; i < n; i++){
                        for (int j = 0; j < m; j++){
                                char tmp;
                                cin >> tmp;
                                if (tmp == '@'){
                                        map[i][j] = 1;
                                }
                        }
                }
                cin >> sx >> sy >> ex >> ey;
                ans = 114514;
                dfs(sx, sy, 0);
                cout << ans << endl;;
        }
        return 0;
}

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-9-24 20:39:49 | 显示全部楼层
此贴是我有病,已经改分类,就别回答了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-9-24 20:34:28 | 显示全部楼层
这段代码中的死循环问题是因为在判断边界时使用了分号,导致后面的语句一直执行。应该使用大括号将语句块括起来。

另外,这段代码中的 dfs 函数只是简单的深度优先搜索,并没有使用任何剪枝技巧,因此效率较低。可以考虑使用 A* 算法等更高效的搜索算法来解决这个问题。

以下是修改后的代码:
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;

const int MAXN = 505;
const int INF = 0x3f3f3f3f;

int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
int map[MAXN][MAXN];
int n, m, sx, sy, ex, ey, ans;
int dis[MAXN][MAXN];

struct Node {
    int x, y, f;
    bool operator<(const Node& other) const {
        return f > other.f;
    }
};

bool isValid(int x, int y) {
    return x >= 0 && x < n && y >= 0 && y < m;
}

void Astar() {
    priority_queue<Node> pq;
    memset(dis, INF, sizeof(dis));
    pq.push({sx, sy, 0});
    dis[sx][sy] = 0;
    while (!pq.empty()) {
        Node cur = pq.top();
        pq.pop();
        int x = cur.x, y = cur.y;
        if (x == ex && y == ey) {
            ans = dis[x][y];
            return;
        }
        if (dis[x][y] < cur.f) continue;
        for (int i = 0; i < 4; i++) {
            int nx = x + dx[ i], ny = y + dy[ i];
            if (!isValid(nx, ny)) continue;
            int nd = dis[x][y] + (map[nx][ny] != map[x][y]);
            if (nd < dis[nx][ny]) {
                dis[nx][ny] = nd;
                pq.push({nx, ny, nd + abs(nx - ex) + abs(ny - ey)});
            }
        }
    }
}

int main() {
    while (cin >> n >> m && n && m) {
        memset(map, 0, sizeof(map));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                char tmp;
                cin >> tmp;
                if (tmp == '@') {
                    map[ i][j] = 1;
                }
            }
        }
        cin >> sx >> sy >> ex >> ey;
        ans = INF;
        Astar();
        cout << ans << endl;
    }
    return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-9-24 20:34:39 | 显示全部楼层
你的代码中有一个问题导致了死循环:在dfs函数中,你没有对已经访问过的位置进行标记,导致程序会一直在同一个位置循环遍历。

解决方法是在进入一个新的位置之前,先将该位置标记为已访问(比如将其值设为-1),这样在下次遇到该位置时就可以跳过。

以下是对你的代码做出修改后的版本:
#include <iostream>using namespace std;int dx[] = {-1, 1, 0, 0};int dy[] = {0, 0, -1, 1};int map[505][505];int n, m, sx, sy, ex, ey, ans;void dfs(int x, int y, int v) {    if (x == ex && y == ey) {        if (v < ans)            ans = v;        return;    }    map[x][y] = -1;  // 标记当前位置为已访问    for (int i = 0; i < 4; i++) {        int xx = x + dx[i];        int yy = y + dy[i];        if (xx >= 0 && xx < n && yy >= 0 && yy < m && map[xx][yy] != -1) {            int vv = v;            if (map[xx][yy] != map[x][y])                vv++;            dfs(xx, yy, vv);        }    }    map[x][y] = 0;  // 恢复当前位置的状态}int main() {    while (true) {        cin >> n >> m;        if (n == 0 && m == 0) {            return 0;        }        for (int i = 0; i < n; i++) {            for (int j = 0; j < m; j++) {                char tmp;                cin >> tmp;                if (tmp == '@') {                    map[i][j] = 1;                } else {                    map[i][j] = 0;                }            }        }        cin >> sx >> sy >> ex >> ey;        ans = 114514;        dfs(sx, sy, 0);        cout << ans << endl;    }    return 0;}
请根据以上修改尝试重新运行代码并测试是否成功解决了死循环的问题。如果还有其他问题,请随时提问。

球一个最佳答案谢谢啦!这对我非常重要!
回答可能有误,多多谅解!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-9-24 20:34:44 | 显示全部楼层
你的代码中的 DFS 函数有一个逻辑错误,在判断 (xx == ex && yy == ey) 时,应该将 vv < ans 的条件加在外层的 if 语句中,而不是放在内层的 else 语句中。

这样做的目的是,当 (xx == ex && yy == ey) 成立时,如果 vv 小于 ans,就更新 ans 的值;否则,直接跳过当前循环。如果将 vv < ans 放在内层的 else 语句中,当 (xx == ex && yy == ey) 成立时,如果 vv 大于等于 ans,就无法跳过当前循环,从而导致死循环。

以下是经过修改的代码:
#include <iostream>
using namespace std;

int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
int map[505][505];
int n, m, sx, sy, ex, ey, ans;

void dfs(int x, int y, int v) {
    for (int i = 0; i < 4; i++) {
        int xx = x + dx[ i];
        int yy = y + dy[ i];
        
        if (xx >= 0 && xx < n && yy >= 0 && yy < m) {
            int vv = v;
            if (map[xx][yy] != map[x][y])
                vv++;
            
            if (xx == ex && yy == ey) {
                if (vv < ans)
                    ans = vv;
            } else {
                dfs(xx, yy, vv);
            }
        }
    }
}

int main() {
    while (true) {
        cin >> n >> m;
        if (n == 0 && m == 0) {
            return 0;
        }
        
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                char tmp;
                cin >> tmp;
                if (tmp == '@') {
                    map[ i][j] = 1;
                }
            }
        }
        
        cin >> sx >> sy >> ex >> ey;
        ans = 114514;
        dfs(sx, sy, 0);
        cout << ans << endl;
    }
    
    return 0;
}

这样修改后的代码应该能够解决死循环的问题,正常运行并给出正确结果。希望能对你有所帮助!
如果问题已经解决,请设置最佳答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-9-24 20:35:40 | 显示全部楼层
原来不止我一个
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-9-24 20:38:26 | 显示全部楼层
tommyyu 发表于 2023-9-24 20:35
原来不止我一个

我承认我是小丑,开学后太久没写题退化了,原来没写vis数组
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-9-24 20:42:32 | 显示全部楼层
陈尚涵 发表于 2023-9-24 20:39
此贴是我有病,已经改分类,就别回答了

鱼币给我吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-9-24 20:44:18 | 显示全部楼层

给我个原因说服自己
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-9-24 20:46:52 | 显示全部楼层
陈尚涵 发表于 2023-9-24 20:44
给我个原因说服自己

因为你无法取回悬赏,并且如果给我了,可以给你一些
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-9-24 20:51:09 | 显示全部楼层
liuhongrun2022 发表于 2023-9-24 20:46
因为你无法取回悬赏,并且如果给我了,可以给你一些

等于说这样还是我亏了,但你赚了,这可不行
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-9-24 21:00:53 | 显示全部楼层
普及+提高
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-9-24 21:01:30 | 显示全部楼层
我还是泰拉了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-9-24 21:09:01 | 显示全部楼层
陈尚涵 发表于 2023-9-24 20:51
等于说这样还是我亏了,但你赚了,这可不行

我要15鱼币,给你25
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-9-24 21:10:03 | 显示全部楼层
陈尚涵 发表于 2023-9-24 20:51
等于说这样还是我亏了,但你赚了,这可不行

给的话你还可以得到,不给可一分不得
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-9-25 21:15:21 | 显示全部楼层
#include<iostream>
#include<cstdio>
#include<deque>
using namespace std;
char sz[505][505];
long long a[500][500];
long long n,m,qx,qy,zx,zy;
long long fx[4]={0,0,1,-1};//控制移动的数组
long long fy[4]={1,-1,0,0};
deque<int>qz;//3个双端队列
deque<int>xd;
deque<int>yd;
long long x,y,z;
void sddl()
{
    while(xd.empty()!=true&&yd.empty()!=true)//不空不走
    {
        x=xd.front();//这个是获取队列的头部元素
        y=yd.front();
        z=qz.front();
        if(x==zx&&y==zy)
        {
            while (xd.empty()!=true)xd.pop_front();//清空队列,我之前因为没清空疯狂80分
            while (yd.empty()!=true)yd.pop_front();
            while (qz.empty()!=true)qz.pop_front();
            cout<<z<<endl;
            return;
        }
        xd.pop_front();
        yd.pop_front();
        qz.pop_front();
        for(int i=0;i<4;i++)
        {
            if(x+fx[i]>=0&&x+fx[i]<n&&y+fy[i]>=0&&y+fy[i]<m)//判断越界
            {
                if(a[x+fx[i]][y+fy[i]]==0)//标记来过没
                {
                    a[x+fx[i]][y+fy[i]]=1;
                    if(sz[x+fx[i]][y+fy[i]]==sz[x][y])//走这个不需要花费,走起
                    {
                        xd.push_front(x+fx[i]);//这个是插入到头部的意思
                        yd.push_front(y+fy[i]);
                        qz.push_front(z);
                    }else//花费1点
                    {
                        xd.push_back(x+fx[i]);//这个是插入到尾部的意思
                        yd.push_back(y+fy[i]);
                        qz.push_back(z+1);
                    } 
                }
            }
        }
    }
    return;
}
int main()
{
    while(true)
    {
        scanf("%lld%lld",&n,&m);
        if(n==0&&m==0)
        {
            return 0;
        }
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                cin>>sz[i][j];
                a[i][j]=0;
            }
        }
        scanf("%lld%lld%lld%lld",&qx,&qy,&zx,&zy);
        a[qx][qy]=1;//省一下
        xd.push_front(qx);//这个是插入到头部的意思
        yd.push_front(qy);
        qz.push_front(0);
        sddl();
    }
    return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-23 23:48

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表