图论——欧拉回路/欧拉路径

pku1780:

给定长度n,要求给出一个最短的字符串,这个字符串包含所有的由0~9组成的长度为n的子串。如果有多个,那么选择字典序最小的一个。

解法:欧拉回路。这算是一个经典问题吧,将所有可能形成的字符串看成图中的边,假如一条边是12345,那么他的两个顶点分别为1234/2345。。就这样建图然后求欧拉回路就可以了。注意不要使用递归,会爆掉堆栈。。。改成回溯写法就好了。用了一下goto语句,感觉goto在这种模拟递归栈的程序中挺好用的。

View Code
 1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 using namespace std;
5
6 const int N = 1000010;
7
8 const int M[7] = {1, 10, 100, 1000, 10000, 100000, 1000000};
9
10 int n, cnt, h[N/10+10], nxt[N], v[N], sv[N], ans[N];
11 bool visit[N];
12
13 char str[7][N+10];
14
15 void solve()
16 {
17 int i, u, p, depth, top, ct = 0;
18 depth = top = 0;
19 sv[depth] = 0;
20 goto now;
21 start:
22 while(depth != -1)
23 {
24 now:
25 u = sv[depth];
26 for(p = h[u]; p != -1; p = nxt[p])
27 if(!visit[p])
28 {
29 visit[p] = true;
30 h[u] = nxt[p];
31 depth++;
32 sv[depth] = v[p];
33 goto start;
34 }
35 ans[top++] = sv[depth];
36 depth--;
37 }
38 for(i = n-1; i > 0; i--)
39 {
40 str[n][ct++] = (char)(ans[top-1]/M[i-1]) + '0';
41 ans[top-1] /= M[i-1];
42 }
43 for(i = top-2; i >= 0; i--) str[n][ct++] = (char)(ans[i]%10) + '0';
44 str[n][ct] = '\0';
45 }
46
47 int main()
48 {
49 int i, a, b;
50 for(n = 2; n <= 6; n++)
51 {
52 if(!n) break;
53 if(n == 1) printf("0123456789\n");
54 else
55 {
56 cnt = 0;
57 memset(h, -1, sizeof(h));
58 for(i = M[n]-1; i >= 0; i--)
59 {
60 a = i/M[1];
61 b = i%M[n-1];
62 v[cnt] = b;
63 nxt[cnt] = h[a];
64 h[a] = cnt++;
65 }
66 memset(visit, false, sizeof(visit));
67 solve();
68 }
69 }
70 while(scanf("%d", &n) != EOF)
71 {
72 if(!n) break;
73 if(n == 1) puts("0123456789");
74 else puts(str[n]);
75 //printf("%d\n", strlen(str[n]));
76 }
77 return 0;
78 }

你可能感兴趣的:(图论)