zoukankan      html  css  js  c++  java
  • poj2337

    题意:给定一些单词,如果一个单词的尾字母与另一个的首字母相同则可以连接。问是否可以每个单词用一次,将所有单词连接,可以则输出字典序最小的序列。

    分析:把每个字母作为一个结点。每个单词作为一条边。这样就可以把问题转化为欧拉路径。现判断欧拉路径是否存在。若存在则找到欧拉路径,找的方法是,先找到出度>入度(无欧拉回路)的结点,从起点开始,dfs(v,e),v是当前结点,e是到v的边。用vis数组记录某条边是否被访问过,从v开始继续搜索未访问过的边。每层dfs结束时把该层的边入栈。dfs整个结束后,把边依次出栈,得到的就是欧拉路径。

    void dfs(int v, int e)
    {
        vis[e] = true;
        for (int i = head[v]; i != -1; i = edge[i].next)
            if (!vis[i])
                dfs(edge[i].v, i);
        stk[top++] = e;
    }

    本题要求字典序最小,那么在dfs的时候就每次先访问字典序最小的边(原因很难说清),具体做法就是把边插入邻接表的时候冒泡一下,维护邻接表有序。当有欧拉回路时还要注意起点的选择,要使得路径的第一条边最小。

    View Code
    #include <iostream>
    #include
    <cstdio>
    #include
    <cstdlib>
    #include
    <cstring>
    using namespace std;

    #define maxn 30
    #define maxl 25
    #define maxm 1005

    struct Edge
    {
    int v, next, id;
    } edge[maxm];

    int n, m;
    char word[maxm][maxl];
    int father[maxn];
    int stk[maxm];
    int in[maxn], out[maxn];
    int head[maxn];
    int ecount;
    int top, s;
    bool vis[maxm];
    bool rep;

    int getanc(int a)
    {
    if (a == father[a])
    return a;
    return father[a] = getanc(father[a]);
    }

    void merge(int a, int b)
    {
    father[getanc(a)]
    = getanc(b);
    }

    void addedge(int a, int b, int c)
    {
    edge[ecount].next
    = head[a];
    edge[ecount].id
    = c;
    edge[ecount].v
    = b;
    head[a]
    = ecount++;
    int temp = head[a];
    while (edge[temp].next != -1)
    {
    int u = edge[temp].id;
    int v = edge[edge[temp].next].id;
    if (strcmp(word[u], word[v]) > 0)
    {
    swap(edge[temp].v, edge[edge[temp].next].v);
    swap(edge[temp].id, edge[edge[temp].next].id);
    }
    temp
    = edge[temp].next;
    }
    }
    void input()
    {
    for (int i = 0; i < n; i++)
    father[i]
    = i;
    memset(
    in, 0, sizeof(in));
    memset(
    out, 0, sizeof(out));
    ecount
    = 0;
    memset(head,
    -1, sizeof(head));
    scanf(
    "%d", &m);
    for (int i = 0; i < m; i++)
    {
    scanf(
    "%s", word[i]);
    int a = word[i][0] - 'a';
    int b = word[i][strlen(word[i]) - 1] - 'a';
    addedge(a, b, i);
    merge(a, b);
    in[b]++;
    out[a]++;
    }
    }

    bool ok()
    {
    s
    = 0;
    int cnt1 = 0, cnt2 = 0;
    for (int i = 0; i < n; i++)
    {
    if (abs(in[i] - out[i]) > 1)
    return false;
    if (in[i] - out[i] == 1)
    cnt1
    ++;
    if (out[i] - in[i] == 1)
    {
    s
    = i;
    cnt2
    ++;
    }
    }
    if (cnt1 == 0 && cnt2 == 0)
    rep
    = true;
    else
    rep
    = false;
    if (cnt1 > 1 || cnt2 > 1 || cnt1 != cnt2)
    return false;

    cnt1
    = 0;
    for (int i = 0; i < n; i++)
    if (i == father[i] && (in[i] | out[i]))
    cnt1
    ++;
    if (cnt1 > 1)
    return false;

    bool first = true;
    if (rep)
    for (int i = 0; i < n; i++)
    if (head[i] != -1 && (first || strcmp(word[edge[head[s]].id], word[edge[head[i]].id]) > 0))
    {
    first
    = false;
    s
    = i;
    }
    return true;
    }

    void dfs(int v, int e)
    {
    vis[e]
    = true;
    for (int i = head[v]; i != -1; i = edge[i].next)
    if (!vis[i])
    dfs(edge[i].v, i);
    stk[top
    ++] = e;
    }

    void work()
    {
    memset(vis,
    0, sizeof(vis));
    top
    = 0;
    dfs(s, ecount);
    }

    void print()
    {
    top
    --;
    printf(
    "%s", word[edge[stk[top - 1]].id]);
    top
    --;
    while (top > 0)
    {
    printf(
    ".%s", word[edge[stk[top - 1]].id]);
    top
    --;
    }
    putchar(
    '\n');
    }

    int main()
    {
    //freopen("t.txt", "r", stdin);
    int t;
    scanf(
    "%d", &t);
    while (t--)
    {
    n
    = 26;
    input();
    if (!ok())
    {
    printf(
    "***\n");
    continue;
    }
    else
    work();
    print();
    }
    return 0;
    }
  • 相关阅读:
    了解HTTP Header之User-Agent和HTTP协议的响应码
    怎样才算一个优秀的管理者
    ldpi、mdpi、hdpi、xhdpi、xxhdpi (无内容,待填)
    手把手教做小偷采集
    java中碰到无法解决的问题:无法访问类的getter访问器
    简单的加密解密处理
    Java中处理二进制移位
    Java中实现String.padLeft和String.padRight
    这短短几行代码价值一万
    从一篇文章中检查特定单词出现数量和第一次出现位置
  • 原文地址:https://www.cnblogs.com/rainydays/p/2115906.html
Copyright © 2011-2022 走看看