3 3 1 2 2 3 1 3 4 4 1 4 2 4 2 3 1 3
1 2 3 1 4 2 3
唉。。
脑残经常有,昨天特别多。很简单的一个dfs竟然从晚上搞到半夜。。。总算是解决了
题目分析:n个点m个关系,求一个序列,每个点与相邻2个点都有关系,首尾2个点算相邻的。
题目分析:因为每个点都至少与一半以上的人有关系,所以此题明显有解,然后就是简单的dfs输出路径就可以了。
比赛的时候脑一残将回溯的标记放在回溯里面,导致一直TLE,后来男神随便写了一个邻接表不带回溯的交了就过了。。。
比赛完又研究了一下此题。
先上一个正确的代码(回溯):
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 170; const int M = 100005; int path[N]; int head[N]; bool fuck[N][N]; bool flag[N]; int table[N][N + 1]; struct node { int to,next; }lcm[M]; int num; int n,m; bool ok; void build(int s,int e) { lcm[num].to = e; lcm[num].next = head[s]; head[s] = num ++; } void dfs(int cur,int dp) { if(ok) return; path[dp] = cur; if(dp == n) { if(fuck[path[1]][path[n]] == true) { int ii; for(ii = 1;ii < n;ii ++) printf("%d ",path[ii]); printf("%d\n",path[ii]); ok = true; } return; } int i; for(i = head[cur];i != -1;i = lcm[i].next) { if(flag[lcm[i].to] == false) { flag[lcm[i].to] = true; dfs(lcm[i].to,dp + 1); if(ok) return; flag[lcm[i].to] = false; } } } int main() { int i,a,b; while(scanf("%d%d",&n,&m) != EOF) { num = 0; memset(head,-1,sizeof(head)); memset(fuck,false,sizeof(fuck)); memset(flag,false,sizeof(flag)); while(m --) { scanf("%d%d",&a,&b); if(fuck[a][b] == false) { build(a,b); build(b,a); fuck[a][b] = fuck[b][a] = true; } } ok = false; flag[1] = true; dfs(1,1); } return 0; }
版本一:回溯标记在dfs里面:
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 170; const int M = 100005; int path[N]; int head[N]; bool fuck[N][N]; bool flag[N]; int table[N][N + 1]; struct node { int to,next; }lcm[M]; int num; int n,m; bool ok; void build(int s,int e) { lcm[num].to = e; lcm[num].next = head[s]; head[s] = num ++; } void dfs(int cur,int dp) { if(ok) return; path[dp] = cur; flag[cur] = true; if(dp == n) { flag[cur] = false;//这里!!!少了就TLE了。。。 if(fuck[path[1]][path[n]] == true) { int ii; for(ii = 1;ii < n;ii ++) printf("%d ",path[ii]); printf("%d\n",path[ii]); ok = true; } return; } int i; for(i = head[cur];i != -1;i = lcm[i].next)//for(i = 1;i <= table[cur][0];i ++) { if(flag[lcm[i].to] == false) { dfs(lcm[i].to,dp + 1); if(ok) return; } } flag[cur] = false; } int main() { int i,a,b; while(scanf("%d%d",&n,&m) != EOF) { num = 0; memset(head,-1,sizeof(head)); memset(fuck,false,sizeof(fuck)); memset(flag,false,sizeof(flag)); while(m --) { scanf("%d%d",&a,&b); if(fuck[a][b] == false) { build(a,b); build(b,a); fuck[a][b] = fuck[b][a] = true; } } ok = false; dfs(1,1); } return 0; }
错误版本二:非回溯版:
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 170; const int M = 100005; int path[N]; int head[N]; bool fuck[N][N]; bool flag[N]; int table[N][N + 1]; struct node { int to,next; }lcm[M]; int num; int n,m; bool ok; void build(int s,int e) { lcm[num].to = e; lcm[num].next = head[s]; head[s] = num ++; } void dfs(int cur,int dp) { if(ok) return; path[dp] = cur; if(dp == n) { if(fuck[path[1]][path[n]] == true) { int ii; for(ii = 1;ii < n;ii ++) printf("%d ",path[ii]); printf("%d\n",path[ii]); ok = true; } return; } int i; for(i = head[cur];i != -1;i = lcm[i].next) { if(flag[lcm[i].to] == false) { flag[lcm[i].to] = true; dfs(lcm[i].to,dp + 1); if(ok) return; } } } int main() { int i,a,b; while(scanf("%d%d",&n,&m) != EOF) { num = 0; memset(head,-1,sizeof(head)); memset(fuck,false,sizeof(fuck)); memset(flag,false,sizeof(flag)); while(m --) { scanf("%d%d",&a,&b); if(fuck[a][b] == false) { build(a,b); build(b,a); fuck[a][b] = fuck[b][a] = true; } } ok = false; for(i = 1;i <= n && !ok;i ++) { memset(flag,false,sizeof(flag)); flag[i] = true; dfs(i,1); } } return 0; }
不信可以试试这组数据:
6 10
1 2
2 6
1 6
5 1
1 4
6 3
5 2
2 4
3 5
4 3
这题数据弱了,所以不带回溯枚举起点也是可以AC的,但AC并不代表就是正确的。
友情鸣谢:
感谢@kill_trick 帮忙找到了第一个问题。
感谢u010228612 提供上面一组数据。
还是太年轻了啊啊。。。