HDU 2894(欧拉回路)

这个题暴搜10分钟写出来了,也AC了。但听XLK和LYD神牛讲的欧拉回路的方法,真心跪了!

XLK题解(有改动):

很显然,第一问的答案就是2^n

第二问,构造一个有2^(n-1)个节点的图,对应2^(n-1)n-1位二进制数。从代表数k的节点(0<=k<2^(n-1))向代表数(k<<1)&(1<<n-1)的节点,和代表数(k<<1)&(1<<n-1)+1的节点分别连一条边。可以发现这样的图中,所有点的入度和出度都是2,因此这是一个欧拉图。因此我们从0号点开始dfs寻找一个欧拉回路,回溯的时候记录到栈中,最后倒序输出即可。因为要求字典序最小,dfs的时候要注意搜索顺序,先走0边,再走1边。这个算法寻找欧拉回路,每个点、每条边只访问一次,是O(V+E)级别的。

时间复杂度O(2^n),预计得分100分。

 

暴搜代码:

 

View Code
 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <iostream>
 4 #include <cstring>
 5 using namespace std;
 6 bool fg,d[1<<15],vis[1<<15];
 7 int tot,k;
 8 void read()
 9 {
10     memset(vis,0,sizeof vis);
11     fg=false;
12     tot=1<<k;
13 }
14 bool check()
15 {
16     int i=1,j=tot+1;
17     for(;i<=k-1;i++,j++)
18     {
19         if(d[i]!=d[j]) return false;
20     }
21     fg=true;
22     for(i=1;i<=tot;i++) printf("%d",d[i]);
23 }
24 void dfs(int step,int num)
25 {
26     if(fg) return;
27     if(step==tot)
28     {
29         check();
30         return;
31     }
32     for(int i=0;i<tot;i++)
33     {
34         if(!vis[i])
35         {
36             int sk;
37             if((num>>(k-1))==1) sk=num-(1<<(k-1));
38             else sk=num;
39             if(sk==(i>>1))
40             {
41                 d[step+k]=i&1;
42                 vis[i]=true;
43                 dfs(step+1,i);
44                 vis[i]=false;
45             }
46         }
47     }
48 }
49 void go()
50 {
51     printf("%d ",tot);
52     for(int i=1;i<=k;i++) d[i]=0;
53     vis[0]=true;
54     dfs(1,0);
55     printf("\n");
56 }
57 int main()
58 {
59     while(scanf("%d",&k)!=EOF)
60     {
61         read();
62         go();
63     }
64     return 0;
65 }

 

欧拉回路代码:

View Code
 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cstring>
 4 using namespace std;
 5 int p,d[1<<15],n;
 6 bool vis[1<<15];
 7 void prev()
 8 {
 9     memset(vis,0,sizeof vis);
10     p=0;
11 }
12 void dfs(int u)
13 {
14     int to1=(u<<1)&((1<<n)-1);
15     int to2=to1+1;
16     if(!vis[to1])
17     {
18         vis[to1]=true;
19         dfs(to1);
20         d[++p]=0;
21     }
22     if(!vis[to2])
23     {
24         vis[to2]=true;
25         dfs(to2);
26         d[++p]=1;
27     }
28 }
29 void go()
30 {
31     dfs(0);
32     printf("%d ",1<<n);
33     for(int i=1;i<n;i++) printf("0");
34     for(int i=p;i>=n;i--) printf("%d",d[i]);
35     printf("\n");
36 }
37 int main()
38 {
39     while(scanf("%d",&n)!=EOF)
40     {
41         prev();
42         go();
43     }
44     return 0;
45 }

后记:

由于紧张备战NOIP考试,所以,难题和新算法就都暂时不学了,把基础巩固好,发现基础太弱了,难题也不会。。

 

没有人能阻止我前进的步伐,除了我自己!
原文地址:https://www.cnblogs.com/proverbs/p/2649984.html