解法:先将每个点之间的可达性用c[][]记录,为0的话代表可以直接走到。但是如果要进行像3 1 2 这样的走法的话必须要先经过他们中间的点2,否则是不能走的。
用c[i][j]记录i和j之间必须要经过的点。然后进行dfs搜索即可。
经过这道题,自己对dfs的递归过程又有了更加深刻的了解。一开始的时候对dfs里面的参数有些疑虑,-->像这样dfs(s[0],0),但是这样的话,每次都要先判断c[x][s[i]]
这样是错误的。dfs(0,0)的话,因为0与1~9都是可以直接到达的(0是自己添加的),所以可以得出所有情况。还有就是想要记录路径的时候要注意,看注释。
#include<iostream> #include<string> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int T,n,ans; int s[20],path[20]; int c[20][20]; int vis[20]; int v[150000][12]; void dfs(int x,int sum) { if(sum>=n) { for(int i=0;i<n;i++)//记录路径 v[ans][i]=path[i]; ans++; return ; } for(int i=0;i<n;i++) { if(!vis[s[i]]) { if(c[x][s[i]]==0) { path[sum]=s[i]; // v[ans][sum]=s[i]; ans前面的都为空,并未赋值,所以错误 vis[s[i]]=1; dfs(s[i],sum+1); vis[s[i]]=0; } else if(c[x][s[i]]&&vis[c[x][s[i]]]==1) { path[sum]=s[i]; //v[ans][sum]=s[i]; vis[s[i]]=1; dfs(s[i],sum+1); vis[s[i]]=0; } } } } int main() { memset(c,0,sizeof(c)); c[1][3]=2,c[3][1]=2; c[1][7]=4,c[7][1]=4; c[1][9]=5,c[9][1]=5; c[2][8]=5,c[8][2]=5; c[3][9]=6,c[9][3]=6; c[3][7]=5,c[7][3]=5; c[4][6]=5,c[6][4]=5; c[7][9]=8,c[9][7]=8; scanf("%d",&T); while(T--) { scanf("%d",&n); memset(vis,0,sizeof(vis)); ans=0; for(int i=0;i<n;i++) scanf("%d",&s[i]); sort(s,s+n); dfs(0,0);//0与所有的点都是连接可以到达的 printf("%d\n",ans); for(int i=0;i<ans;i++) { printf("%d",v[i][0]); for(int j=1;j<n;j++) printf(" %d",v[i][j]); printf("\n"); } } return 0; }
另附dfs生成全排列的算法,是这道题的原型。
#include<iostream> #include<cstring> using namespace std; int vis[10],n; int ans[10]; void dfs(int sum) { if(sum>n) { int first=0; for(int i=1;i<=n;i++) { if(first++) cout<<" "; cout<<ans[i]; } cout<<endl; } for(int i=1;i<=n;i++) { if(!vis[i]) { vis[i]=1; ans[sum]=i; dfs(sum+1); vis[i]=0; } } } int main() { cin>>n; memset(vis,0,sizeof(vis)); dfs(1); }
dfs()里面的参数只用记录当前总数即可。也可采取在主程序中枚举起点的办法。
时间: 2024-10-14 12:22:27