NYOJ99 单词拼接

来源:互联网 发布:mac itunes 12.7 铃声 编辑:程序博客网 时间:2024/06/07 03:08
题目分析:
其实上这道题把给的单词转化成一个图,然后考察这个图是否具有一个欧拉回路。

一个图具有欧拉回路的充要条件是这个图是连通的,并且只有0或2个奇点。出度比入度大一的作为起点,出度比入度小一的作为终点。

最后用递归搜索路径

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char s[1000][35];
int F[30], Out[30], In[30], n;  // F[]数组为并查集的数组 Out[]为每个字符的出度 In[]为每个字符的入度
int stack[1005], used[1005];   // stack[]数组为保存的路径  usec[]数组为标记是否被选用过
bool flag ;
int find(int x)  // 并查集的合并集合
{
    return F[x] == x ? x : F[x] = find(F[x]);
}
int cmp(const void *a, const void *b)  // 把数组各个特定长度按照升序排序
{
    char *p1 = (char *)a;
    char *p2 = (char *)b;
    return strcmp(p1, p2); //   这是按升序排序  return strcmp(p2, p1) 这是按降序排序
}
void DFS(char first, int cur)   //搜索打印方案
{
    if(cur==n || flag)
    {
        flag = 1;
        return ;
    }
    int l = 0, r = n-1, m;    //二分搜索查找首字母为first的单词
    while(l <= r)
    {
        m = (l+r)/2;
        if(s[m][0] == first)
            break;
        else if(s[m][0] > first)
            r = m-1;
        else
            l = m+1;
    }
    while(s[m][0]==first && m>=0)  //找到first第一次出现的单词保证字典序最小
        m--;
    for(int i = m+1; s[i][0] == first; i++)
                if(!used[i])
    {
        stack[cur] = i;  // 保存查找到的路径
        used[i] = 1;
        DFS(s[i][strlen(s[i])-1], cur+1);
        if(flag)
            return ;
        used[i] = 0;
    }
}
int main()
{
    int T;
//    freopen("Input.txt", "r", stdin);
//    freopen("O.txt", "w", stdout);
    scanf("%d", &T);
    while(T--)
    {
        memset(used, 0, sizeof(used));
        memset(Out, 0, sizeof(Out));
        memset(In, 0, sizeof(In));
        for(int i = 1; i <= 26; i++)  //初始化并查集
            F[i] = i;
        scanf("%d", &n);
        for(int i = 0; i < n; i++)
        {
            scanf("%s", s[i]);
            int len = strlen(s[i]);
            int q = s[i][0]-'a'+1;
            int p = s[i][len-1]-'a'+1;
            Out[q]++; //统计每个出现字符的出度
            In[p]++;  //统计每个出现字符的入度
            int x = find(q);
            int y = find(p);
            if(x != y)  // 把属于相同集合的给合并
                F[q] = y;
        }
        qsort(s, n, 35*sizeof(char), cmp);  
        int count1 = 0, count2 = 0, count3 = 0, count4 = 0, k = 1;
        for(int i = 1; i <= 26; i++)
            if(Out[i] || In[i])
            {
                if(F[i] == i)
                    count1++;  //统计这总共有几个集合
                if(Out[i]-In[i]==1)
                {
                    count3++;  //统计出度比入度大一的个数    这是单词拼接的开始
                    k = i;   //记录开始的位置
                }
                if(In[i]-Out[i]==1)
                    count4++;  //统计入度比出度大一的个数    这是单词拼接的结束
                if(Out[i] != In[i])
                    count2++;
            }
        if(count1==1 && count2==count3+count4 && (count2==0 || count2==2))
        {
            flag = 0;
            DFS(k+'a'-1, 0);
            for(int i = 0; i < n-1; i++)
                printf("%s.", s[stack[i]]);
            printf("%s\n", s[stack[n-1]]);
        }
        else
            printf("***\n");
    }
    return 0;
}

0 0
原创粉丝点击