zoukankan      html  css  js  c++  java
  • UVA10129———欧拉道路

    题目

    输入n(n≤100000)个单词,是否可以把所有这些单词排成一个序列,使得每个单词的第一个字母和上一个单词的最后一个字母相同(例如 acm,malform,mouse)。每个单词最多包含1000个小写字母。输入中可以有重复单词。

    解题思路

    把字母看作结点,单词看作有向边,则问题有解等价于图中存在欧拉道路。有向图中存在欧拉道路的条件有两个:一是底图(忽略边的方向后得到的无向图)连通,二是度数满足不存在奇点或奇点数为2。度数判读只要在输入时记录每个顶点的入度出度,而连通性判断有两种:DFS和并查集。

    代码实现

    dfs判断连通性+特判入出度

     1 #include<stdio.h>
     2 #include<cstring>
     3 using namespace std;
     4 
     5 const int maxn = 26 + 5;
     6 int G[maxn][maxn],in[maxn],out[maxn];
     7 int vis[maxn];        //点是否访问,不是边
     8 int n;
     9 char word[1000 + 10];
    10 
    11 void dfs(int u)
    12 {
    13     vis[u] = 1;
    14     for (int v = 0; v < maxn; v++)  if (G[u][v])
    15     {
    16         G[u][v] = G[v][u] = 0;
    17         //G[u][v]--; G[v][u]--;
    18         dfs(v);
    19     }
    20 }
    21 
    22 int main()
    23 {
    24     int T;
    25     scanf("%d", &T);
    26     while (T--)
    27     {
    28         memset(G, 0, sizeof(G));
    29         memset(in, 0, sizeof(in));
    30         memset(out, 0, sizeof(out));
    31         memset(vis, 0, sizeof(vis));
    32         scanf("%d", &n);
    33         int start;            //起点
    34         while (n--)
    35         {
    36             scanf("%s", word);
    37             int len = strlen(word);
    38             int u = word[0] - 'a', v = word[len - 1] - 'a';
    39             start = u;
    40             vis[u] = vis[v] = -1;    //出现过的标为-1
    41             G[u][v] = G[v][u] = 1;    //连通性按无向图处理
    42             //G[u][v]++; G[v][u]++;
    43             out[u]++;        //度数按有向图处理
    44             in[v]++;
    45         }
    46 
    47         bool flag = true;    //满足要求为true
    48         int s_odd = 0,t_odd = 0;    //起始奇点、结束奇点
    49         for (int i = 0; i < maxn; i++)
    50         {
    51             if (in[i] == out[i])  continue;
    52             if (out[i] == in[i] + 1 && !s_odd) { start = i; s_odd = 1; }
    53             else if (in[i] == out[i] + 1 && !t_odd)  t_odd = 1;
    54             else { flag = false; break; }
    55         }
    56         if (flag)
    57         {
    58             dfs(start);    //也可以不从奇点出发,这个只是判断连通性
    59             for (int i = 0; i < maxn; i++)
    60                 if (vis[i] == -1) { flag = false; break; }
    61         }
    62 
    63         if (flag)  printf("Ordering is possible.
    ");
    64         else  printf("The door cannot be opened.
    ");
    65     }
    66     return 0;
    67 }

    并查集判断连通性+特判入出度

     1 #include<stdio.h>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<string>
     6 #include<cmath>
     7 using namespace std;
     8 
     9 const int maxn = 26 + 5;
    10 int in[maxn], out[maxn], flag[maxn], p[maxn], fa[maxn];
    11 int n;
    12 
    13 void init()
    14 {
    15     for (int i = 0; i < 26; i++)
    16         fa[i] = i;
    17     memset(in, 0, sizeof(in));
    18     memset(out, 0, sizeof(out));
    19     memset(flag, 0, sizeof(flag));
    20     memset(p, 0, sizeof(p));
    21 }
    22 int find(int x)
    23 {
    24     if (fa[x] != x)    return fa[x] = find(fa[x]);
    25     return fa[x];
    26 }
    27 
    28 void unite(int x, int y)
    29 {
    30     int rx = find(x);
    31     int ry = find(y);
    32     fa[rx] = ry;
    33 }
    34 
    35 int main()
    36 {
    37     int T;
    38     int a, b;
    39     string str;
    40     scanf("%d", &T);
    41     while (T--)
    42 {
    43         init();
    44         scanf("%d", &n);
    45         for (int i = 0; i < n; i++)
    46         {
    47             cin >> str;
    48             a = str[0] - 'a';
    49             b = str[str.size() - 1] - 'a';
    50             unite(a, b);
    51             in[a]++;
    52             out[b]++;
    53             flag[a] = flag[b] = 1;
    54         }
    55 
    56         int cnt = 0;    //记录连通分量
    57         int root;
    58         for (int i = 0; i < 26; i++)
    59         {
    60             if (flag[i])
    61             {
    62                 root = find(i);
    63                 break;
    64             }
    65         }
    66 for (int i = 0; i < 26; i++)
    67         {
    68             if (flag[i])
    69                 if (root != find(i)) cnt = 1;
    70         }
    71 
    72         if (cnt) {
    73             printf("The door cannot be opened.
    ");
    74             continue;
    75         }
    76 
    77         int k = 0; //p[i]记录度数不等的
    78         for (int i = 0; i < 26; i++)
    79         {
    80             if (flag[i] && in[i] != out[i])  p[k++] = i;
    81         }
    82         if (k == 0)
    83         {
    84             printf("Ordering is possible.
    ");
    85             continue;
    86         }
    87         if (k == 2 && (in[p[0]] - out[p[0]] == 1 && in[p[1]] - out[p[1]] == -1) || (in[p[0]] - out[p[0]] == -1 && in[p[1]] - out[p[1]] == 1))
    88         {
    89             printf("Ordering is possible.
    ");
    90         continue;
    91         }
    92         else
    93         {
    94             printf("The door cannot be opened.
    ");
    95         }
    96     }
    97     return 0;
    98 }

     参考链接:https://blog.csdn.net/qq_29169749/article/details/51111377

  • 相关阅读:
    图论一角
    入门-k8s部署应用 (三)
    入门-k8s集群环境搭建(二)
    入门-Kubernetes概述 (一)
    shell中获取时间
    Linux shell脚本之 if条件判断 (转)
    linux中shell变量$#等的释义
    shell 的here document 用法 (cat << EOF) (转)
    Homebrew的安装与使用
    docker容器编排 (4)
  • 原文地址:https://www.cnblogs.com/lfri/p/9922028.html
Copyright © 2011-2022 走看看