UVa Problem 10054 The Necklace (项链)

// The Necklace (项链) // PC/UVa IDs: 111002/10054, Popularity: B, Success rate: low Level: 3 // Verdict: Accepted // Submission Date: 2011-10-04 // UVa Run Time: 0.556s // // 版权所有(C)2011,邱秋。metaphysis # yeah dot net // // [Problem Description] // My little sister had a beautiful necklace made of colorful beads. Each two // successive beads in the necklace shared a common color at their meeting point, // as shown below: // // ----green--red----red--white----white--green----green--blue---- // // But, alas! One day, the necklace tore and the beads were scattered all over the // floor. My sister did her best to pick up all the beads, but she is not sure // whether she found them all. Now she has come to me for help. She wants to know // whether it is possible to make a necklace using all the beads she has in the // same way that her original necklace was made. If so, how can the beads be so // arranged? // // Write a program to solve the problem. // // [Input] // The first line of the input contains the integer T , giving the number of test // cases. The first line of each test case contains an integer N (5 ≤ N ≤ 1,000) // giving the number of beads my sister found. Each of the next N lines contains // two integers describing the colors of a bead. Colors are represented by integers // ranging from 1 to 50. // // [Output] // For each test case, print the test case number as shown in the sample output. // If reconstruction is impossible, print the sentence “some beads may be lost” // on a line by itself. Otherwise, print N lines, each with a single bead description // such that for 1 ≤ i ≤ N − 1, the second integer on line i must be the same as // the first integer on line i + 1. Additionally, the second integer on line N // must be equal to the first integer on line 1. There may be many solutions, any // one of which is acceptable. // // Print a blank line between two successive test cases. // // [Sample Input] // 2 // 5 // 1 2 // 2 3 // 3 4 // 4 5 // 5 6 // 5 // 2 1 // 2 2 // 3 4 // 3 1 // 2 4 // // [Sample Output] // Case #1 // some beads may be lost // // Case #2 // 2 1 // 1 3 // 3 4 // 4 2 // 2 2 // // [解题方法] // 若把珠子两端的颜色看作是顶点,珠子本身看成是边,则该题可以建模成欧拉回路问题。需要判断顶点的度 // 是否为都为偶数,若都为偶数才可能包含欧拉回路,然后判断图是否连通,若这两个条件都满足,则肯定存在 // 欧拉回路,找出即可。使用宽度或深度优先遍历确定图的连通性,亦可考虑使用不相交集合并/查数据结构 // (并查集)来实现判断。由于本题有较多的输入输出,在输出换行时,使用 “\n" 而不是 endl 可以减少 // 一些运行时间(使用 endl 时运行时间为 1.668s,因为 endl 在输出换行符后都要立即刷新输出缓存, // 故耗费较多时间)。在提交中还发现,UVa OnlineJudge 中的测试数据都是连通图,判断是否为连通图 // 的一步其实可以省略掉!呵,测试数据还真是较弱...... #include <iostream> #include <cstring> #include <queue> using namespace std; #define MAXV 50 vector < int > edges[MAXV + 1]; int connected[MAXV + 1][MAXV + 1]; int degree[MAXV + 1]; int parent[MAXV + 1]; // 并/查集合的查操作,采用了路径压缩优化。 int find(int x) { return (parent[x] == x) ? x : (parent[x] = find(parent[x])); } // 输出欧拉回路,思路是先找出一个环,然后将此环从图中删除,继续从下一个起点开始找环,将这些环在公 // 共端点连接起来即构成一条欧拉回路。可以使用递归来实现。 void eulerian_cycle(int begin) { for (int to = 1; to <= MAXV; to++) if (connected[begin][to]) { connected[begin][to]--; connected[to][begin]--; eulerian_cycle(to); cout << to << " " << begin << "\n"; } } // 使用宽度优先遍历来判断图是否连通。 bool breadth_first_search(int begin) { bool discovered[MAXV + 1]; // 边数为 0 表示该颜色未出现,标记为已遍历。 for (int c = 1; c <= MAXV; c++) discovered[c] = (edges[c].size() == 0); queue < int > q; q.push(begin); while (!q.empty()) { int vertex = q.front(); q.pop(); for (int v = 0; v < edges[vertex].size(); v++) if (discovered[edges[vertex][v]] == false) { q.push(edges[vertex][v]); discovered[edges[vertex][v]] = true; } } // 尚有未发现的顶点,则图不连通。 for (int c = 1; c <= MAXV; c++) if (discovered[c] == false) return true; return false; } void solve_by_breadth_first_search(void) { int number = 1, cases; // 当前测试序号和测试例数。 int n; // 珠子数。 int cleft, cright; // 珠子左右两端的颜色。 cin >> cases; while (cases--) { memset(connected, 0, sizeof(connected)); for (int c = 1; c <= MAXV; c++) edges[c].clear(); // 建模成无向图,求欧拉回路。 cin >> n; for (int c = 1; c <= n; c++) { cin >> cleft >> cright; edges[cleft].push_back(cright); edges[cright].push_back(cleft); connected[cleft][cright]++; connected[cright][cleft]++; } // 判断是否为连通图,通过一次宽度优先遍历即可确定。找一个起点进行遍历。 int begin = 1; while (!edges[begin].size()) begin++; bool impossible = breadth_first_search(begin); // 若图可连通则判断度是否都为偶数。 if (!impossible) { for (int c = 1; c <= MAXV; c++) if (edges[c].size() & 1) { impossible = true; break; } } cout << "Case #" << number++ << "\n"; if (impossible) cout << "some beads may be lost\n" << endl; else eulerian_cycle(begin); if (cases) cout << "\n"; } } // 使用并查集解题。 void solve_by_union_find(void) { int number = 1, cases; // 当前测试序号和测试例数。 int n; // 珠子数。 int cleft, cright; // 珠子左右两端的颜色。 cin >> cases; while (cases--) { memset(connected, 0, sizeof(connected)); memset(degree, 0, sizeof(degree)); for (int c = 1; c <= MAXV; c++) parent[c] = c; cin >> n; for (int c = 1; c <= n; c++) { cin >> cleft >> cright; connected[cleft][cright]++; connected[cright][cleft]++; degree[cleft]++; degree[cright]++; // 查找 cleft 和 cright 是否位于同一集合,若不位于同一集合,则执行 // 并操作。 int pleft = find(cleft); int pright = find(cright); if (pleft != pright) parent[pleft] = pright; } bool impossible = false; // 判断是否为连通图,先找到一个度不为 0 的顶点作为起始。 int begin = 1; while (!degree[begin]) begin++; int tparent = find(begin); for (int c = 1 + begin; c <= MAXV; c++) if (degree[c] && find(c) != tparent) { impossible = true; break; } // 判断顶点的度数是否都为偶数。 if (!impossible) { for (int c = 1; c <= MAXV; c++) if (degree[c] & 1) { impossible = true; break; } } cout << "Case #" << number++ << "\n"; if (impossible) cout << "some beads may be lost\n"; else eulerian_cycle(begin); if (cases) cout << "\n"; } } int main(int ac, char *av[]) { // 使用宽度优先遍历判断图是否连通,UVa RT 0.556s。 solve_by_breadth_first_search(); // 使用并查集判断图是否连通,UVa RT 0.560s。 // solve_by_union_find(); return 0; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值