问题描述
为了增加公司收入,F公司新开设了物流业务。由于F公司在业界的良好口碑,物流业务一开通即受到了消费者的欢迎,物流业务马上遍及了城市的每条街道。然而,F公司现在只安排了小明一个人负责所有街道的服务。
任务虽然繁重,但是小明有足够的信心,他拿到了城市的地图,准备研究最好的方案。城市中有n个交叉路口,m条街道连接在这些交叉路口之间,每条街道的
首尾都正好连接着一个交叉路口。除开街道的首尾端点,街道不会在其他位置与其他街道相交。每个交叉路口都至少连接着一条街道,有的交叉路口可能只连接着一
条或两条街道。
小明希望设计一个方案,从编号为1的交叉路口出发,每次必须沿街道去往街道另一端的路口,再从新的路口出发去往下一个路口,直到所有的街道都经过了正好一次。
输入格式
输入的第一行包含两个整数n, m,表示交叉路口的数量和街道的数量,交叉路口从1到n标号。
接下来m行,每行两个整数a, b,表示和标号为a的交叉路口和标号为b的交叉路口之间有一条街道,街道是双向的,小明可以从任意一端走向另一端。两个路口之间最多有一条街道。
输出格式
如果小明可以经过每条街道正好一次,则输出一行包含m+1个整数p1, p2, p3, ..., pm+1,表示小明经过的路口的顺序,相邻两个整数之间用一个空格分隔。如果有多种方案满足条件,则输出字典序最小的一种方案,即首先保证p1最小,p1最小的前提下再保证p2最小,依此类推。
如果不存在方案使得小明经过每条街道正好一次,则输出一个整数-1。
样例输入
4 5
1 2
1 3
1 4
2 4
3 4
样例输出
1 2 4 1 3 4
样例说明
城市的地图和小明的路径如下图所示。
样例输入
4 6
1 2
1 3
1 4
2 4
3 4
2 3
样例输出
-1
样例说明
城市的地图如下图所示,不存在满足条件的路径。
评测用例规模与约定
前30%的评测用例满足:1 ≤ n ≤ 10, n-1 ≤ m ≤ 20。
前50%的评测用例满足:1 ≤ n ≤ 100, n-1 ≤ m ≤ 10000。
所有评测用例满足:1 ≤ n ≤ 10000,n-1 ≤ m ≤ 100000。
析:根据题意就能看出来是欧拉路,关于欧拉路,就相当于一笔画,从一个结点出发(这个题是确定了,从1出发),然后把所有的边都走一遍,那么首先,
如果结点有多于2个度为奇数,那么一定不可能,如果有两个奇度结点,那么必须有一个是1,否则就不行了,至于连通性可以用并查集,或者也可以用DFS来判,
最后就是打印路径,这里可以用stack来储存答案,然后DFS去搜,要想字典序小,首先是把所有的点按大小排序,然后在搜的时候优先选择小的,这样字典序就最小。
代码如下:
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iostream> #include <cstring> #include <set> #include <queue> #include <algorithm> #include <vector> #include <map> #include <cctype> #include <cmath> #include <stack> #define freopenr freopen("in.txt", "r", stdin) #define freopenw freopen("out.txt", "w", stdout) using namespace std; typedef long long LL; typedef pair<int, int> P; const int INF = 0x3f3f3f3f; const double inf = 0x3f3f3f3f3f3f; const LL LNF = 0x3f3f3f3f3f3f; const double PI = acos(-1.0); const double eps = 1e-8; const int maxn = 1e4 + 5; const int mod = 1e9 + 7; const int dr[] = {-1, 0, 1, 0}; const int dc[] = {0, 1, 0, -1}; const char *Hex[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"}; int n, m; const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; inline int Min(int a, int b){ return a < b ? a : b; } inline int Max(int a, int b){ return a > b ? a : b; } inline LL Min(LL a, LL b){ return a < b ? a : b; } inline LL Max(LL a, LL b){ return a > b ? a : b; } inline bool is_in(int r, int c){ return r >= 0 && r < n && c >= 0 && c < m; } vector<int> G[maxn]; int p[maxn], in[maxn]; int Find(int x) { return x == p[x] ? x : p[x] = Find(p[x]); } stack<int> ans; bool vis[maxn][maxn]; void dfs(int u){ for(int i = 0; i < G[u].size(); ++i){ int v = G[u][i]; if(!vis[u][v]){ vis[u][v] = vis[v][u] = 1; dfs(v); ans.push(v); } } } bool judge(){ int x = Find(1); int cnt = 0; for(int i = 1; i <= n; ++i){ if(x != Find(i)) return false; if(in[i] & 1) ++cnt; if(cnt > 2) return false; sort(G[i].begin(), G[i].end()); } if(cnt == 2 && in[1] % 2 == 0) return false; return true; } void print(){ printf("1"); while(!ans.empty()){ printf(" %d", ans.top()); ans.pop(); } printf("\n"); } int main(){ while(scanf("%d %d", &n, &m) == 2){ for(int i = 1; i <= n; ++i) G[i].clear(), p[i] = i; memset(in, 0, sizeof in); memset(vis, false, sizeof vis); int u, v; for(int i = 0; i < m; ++i){ scanf("%d %d", &u, &v); G[u].push_back(v); G[v].push_back(u); int x = Find(u); int y = Find(v); if(x != y) p[y] = x; ++in[u]; ++in[v]; } if(!judge()){ printf("-1\n"); continue; } dfs(1); print(); } return 0; }