题目链接。
题目大意:
给很多木棍,两端被涂了颜色。任意两根木棍的相同颜色处可以拼接在一起,问有没有可能将所有的木棍都连起来,成一条直线?
分析:
考点,欧拉道路。
将一根木棍看成一条边,两端的颜色看成两个点,问题成了,能否从无向图的一个结点出发走出一条道路,每条边恰好经过一次。
求法:
如果一个无向图是连通的,且最多有两个奇点(奇点指的是度数是奇数的点),则一定存在欧拉道路。
是否连通可以通过并查集来求。
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <string> using namespace std; const int maxn = 500000+10+10; int deg[maxn], cm, cn, p[maxn]; struct node { struct node *next[26]; int num; }mem[250000*40+10]; node *create() { for(int i=0; i<26; i++) { mem[cm].next[i] = NULL; } mem[cm].num = 0; return &mem[cm++]; } int get_num(node *&root, char s[]) { int len = strlen(s); node *p; if(!root) root = create(); p = root; for(int i=0; i<len; i++) { int k = s[i] - 'a'; if(!p->next[k]) p->next[k] = create(); p = p->next[k]; } if(!p->num) p->num = cn++; return p->num; } int find(int x) { return p[x] == x ? p[x] : (p[x] = find(p[x])); } void Union(int x, int y) { x = find(x), y = find(y); if(x != y) p[x] = y; } int main(){ int u, v; char s1[20], s2[20]; node *root = NULL; cm = 0, cn = 1; memset(deg, 0, sizeof(deg)); for(int i=1; i<maxn; i++) p[i] = i; while(scanf("%s %s", s1, s2) == 2) { u = get_num(root, s1); v = get_num(root, s2); deg[u]++; deg[v]++; Union(u, v); } int pn= 0; bool flag = true; int e = find(1); for(int i=1; i<cn; i++) { //从1开始编号 if(deg[i] % 2 != 0) { pn++; } if(pn > 2 || find(i) != e) { flag = false; break; } } if(flag) printf("Possible "); else printf("Impossible "); return 0; }