图的遍历 | 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; }
在自己思路上修改的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 结构