图的遍历 | 1131地铁图: dfs复杂模拟题

Posted TQCAI

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图的遍历 | 1131地铁图: dfs复杂模拟题相关的知识,希望对你有一定的参考价值。

这题在搞清楚思路绕过坑后,还是可以写的出通过sample data的代码的。但是不能AC,让我很气。

最后查清原因:还是对dfs本质理解的不够。

wa代码:

vis[s]=1;
dfs(s,e,0);

殊不知本题有多个查询数据。如果只调用一遍还可以蒙混过关,但是这样的错误必然导致wa

ac代码:

vis[s]=1;
dfs(s,e,0);
vis[s]=0;

参考柳诺博客修改的AC代码:

技术分享图片
#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <algorithm>
#include <map>


#define I scanf
#define OL puts
#define O printf
#define F(a,b,c) for(a=b;a<c;a++)
#define FF(a,b) for(a=0;a<b;a++)
#define FG(a,b) for(a=b-1;a>=0;a--)
#define LEN 10000
#define MAX 0x06FFFFFF
#define V vector<int>

using namespace std;

vector<int> g[LEN];
int line[LEN][LEN];
int vis[LEN];
vector<int> path;
vector<int> ans;
int min_d=MAX;
int min_ls=MAX;

int N,M,K;

int calc_ls(){
    int cnt=-1,preLine=0;
    for(int i=1;i<path.size();i++){
        if(line[path[i-1]][path[i]]!=preLine) cnt++;
        preLine=line[path[i-1]][path[i]];
    }
    return cnt;
}

void dfs(int s,int e,int d){
    if(s==e){
        int ls=calc_ls();
        if(d<min_d || (d==min_d && ls<min_ls)){
            min_d=d;
            min_ls=ls;
            ans=path;
        }
        return;
    }
    int i;
    FF(i,g[s].size()){
        int o=g[s][i];
        if(!vis[o]){
            vis[o]=1;
            path.push_back(o);
            dfs(o,e,d+1);
            vis[o]=0;
            path.pop_back();
        }
    }

}

void printLine(){
    int s=ans[0];
    int preL=0;
    int i;
    F(i,1,ans.size()){
        if(line[ans[i-1]][ans[i]]!=preL){
            if(preL) printf("Take Line#%d from %04d to %04d.\n",preL,s,ans[i-1]);
            s=ans[i-1];
            preL=line[ans[i-1]][ans[i]]; 
        }
    }
    printf("Take Line#%d from %04d to %04d.\n",preL,s,ans[i-1]);
}

int main(){
//    freopen("1131.txt","r",stdin);
    int s,e,i,j;
    I("%d",&N);
    F(i,1,N+1){
        int pre,p=-1;
        I("%d",&M);
        while(M--){
            pre=p;
            I("%d",&p);
            if(pre>=0){
                g[p].push_back(pre);
                g[pre].push_back(p);
                line[p][pre]=i;
                line[pre][p]=i;
            }
        }
    }
    I("%d",&K);
    while(K--){
        min_d=MAX;
        min_ls=MAX;
        path.clear();
        ans.clear();
        I("%d%d",&s,&e);
        path.push_back(s);
        vis[s]=1;
        dfs(s,e,0);
        vis[s]=0;
        O("%d\n",min_d);
        printLine();
    }
    return 0;
}
View Code

在自己思路上修改的AC代码:(个人认为比柳诺的好理解)

  1 #include <stdio.h>
  2 #include <memory.h>
  3 #include <math.h>
  4 #include <string>
  5 #include <vector>
  6 #include <set>
  7 #include <stack>
  8 #include <queue>
  9 #include <algorithm>
 10 #include <map>
 11 
 12 
 13 #define I scanf
 14 #define OL puts
 15 #define O printf
 16 #define F(a,b,c) for(a=b;a<c;a++)
 17 #define FF(a,b) for(a=0;a<b;a++)
 18 #define FG(a,b) for(a=b-1;a>=0;a--)
 19 #define LEN 10000
 20 #define MAX 0x06FFFFFF
 21 #define V vector<int>
 22 
 23 using namespace std;
 24 
 25 vector<int> g[LEN];
 26 int line[LEN][LEN];
 27 int vis[LEN];
 28 vector<int> path;
 29 vector<int> ans;
 30 int min_d=MAX;
 31 int min_ls=MAX;
 32 
 33 int N,M,K;
 34 
 35 void dfs(int s,int e,int d,int l,int ls){
 36     if(s==e){
 37         if(d<min_d || (d==min_d && ls<min_ls)){
 38             min_d=d;
 39             min_ls=ls;
 40             ans=path;
 41         }
 42         return;
 43     }
 44     int i;
 45     FF(i,g[s].size()){
 46         int o=g[s][i];
 47         if(!vis[o]){
 48             vis[o]=1;
 49             path.push_back(o);
 50             int nl=line[s][o];
 51             int nls=ls;
 52             if(l==0){    //初始结点 
 53                 nls=1;
 54             }else{
 55                 if(nl!=l) nls++;
 56             }
 57             dfs(o,e,d+1,nl,nls);
 58             vis[o]=0;
 59             path.pop_back();
 60         }
 61     }
 62 
 63 }
 64 
 65 void printLine(){
 66     int s=ans[0];
 67     int preL=line[s][ans[1]];
 68     int i;
 69     F(i,1,ans.size()){
 70         if(line[ans[i-1]][ans[i]]!=preL){
 71             printf("Take Line#%d from %04d to %04d.\n",preL,s,ans[i-1]);
 72             s=ans[i-1];
 73             preL=line[ans[i-1]][ans[i]]; 
 74         }
 75     }
 76     printf("Take Line#%d from %04d to %04d.\n",preL,s,ans[i-1]);
 77 }
 78 
 79 int main(){
 80 //    freopen("1131.txt","r",stdin);
 81     int s,e,i,j;
 82     I("%d",&N);
 83     F(i,1,N+1){
 84         int pre,p=-1;
 85         I("%d",&M);
 86         while(M--){
 87             pre=p;
 88             I("%d",&p);
 89             if(pre>=0){
 90                 g[p].push_back(pre);
 91                 g[pre].push_back(p);
 92                 line[p][pre]=i;
 93                 line[pre][p]=i;
 94             }
 95         }
 96     }
 97     I("%d",&K);
 98     while(K--){
 99         min_d=MAX;
100         min_ls=MAX;
101         path.clear();
102         ans.clear();
103         I("%d%d",&s,&e);
104         vis[s]=1;
105         dfs(s,e,0,0,0);
106         vis[s]=0;
107         O("%d\n",ans.size());
108         ans.insert(ans.begin(),s);
109         printLine();
110     }
111     return 0;
112 }

注意点:

① 38 39 行,对维护的最小距离和最小换乘次数进行更新,不要写错(我开始写成了d=min_d ,查了很久的错,蠢哭……)

② 99 100 行,将最小距离和最小换乘次数重新初始化为INF。

③ 106 行,牢记 dfs 结构

 




以上是关于图的遍历 | 1131地铁图: dfs复杂模拟题的主要内容,如果未能解决你的问题,请参考以下文章

PAT甲级1131 Subway Map (30分)(DFS)

算法导论—无向图的遍历(BFS+DFS,MATLAB)

图的遍历:深度优先遍历,广度优先遍历

图的遍历——DFS

图的 DFS 与 BFS 复杂度分析

算法|图的遍历-深度优先搜索(DFS)