poj 1386

来源:互联网 发布:诲女知之乎悔 编辑:程序博客网 时间:2024/06/05 04:29

图论的题目,用并查集判断连通,然后判断欧拉路径存在。

题目中给你n个字符串,问你能不能找到一种排列方案,使前一个单词的尾部字符是下一个单词的首部字母。

这里我们要将问题转化,将一个单词看成一条边。将首尾两个字符分别看做两个节点,中间字母全部忽略

比如数据1:

acmibm

 acm  是一条  a->m的边

ibm    是一条   i->m的边

判断存不存一条欧拉通路能够遍历每一条边,注上述问题的单词已经被我转化为一条有向边,然后前一个单词的尾部字符是下一个单词的首部字母这一条件就是两个单词的共同节点。判断有向图欧拉回路直接统计每一个节点的出入度即可。

注意点:

图可能不连通,要用并查集判断,判断方法就是将一条边上的两个点连接,最后判断所有点是不是一个集合内即可。

 

代码:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;

int F[30];
int find(int x)
{
    if(F[x] == -1)return x;
    else return F[x] = find(F[x]);
}
void bing(int u,int v)
{
    int t1 = find(u);
    int t2 = find(v);
    if(t1 != t2)F[t1] = t2;
}
char str[1010];
int in[30],out[30];
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    int n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        memset(F,-1,sizeof(F));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        int s = -1;
        while(n--)
        {
            scanf("%s",str);
            int len = strlen(str);
            int u = str[0] - 'a';
            int v = str[len-1] - 'a';
            bing(u,v);
            out[u]++;in[v]++;
            if(s == -1)s = u;
        }
        bool flag = true;
        int cc1 = 0,cc2 = 0;
        for(int i = 0;i < 26;i++)
        {
            if(out[i] - in[i] == 1)cc1++;
            else if(out[i] - in[i] == -1) cc2++;
            else if(out[i] != in[i])
                flag = false;
            if(out[i] || in[i])
                if(find(i) != find(s))
                    flag = false;
        }
        if( !( (cc1 == 0 && cc2 == 0) || (cc1 == 1 && cc2 == 1) ) )
      flag = false;
        if(flag)
      printf("Ordering is possible.\n");
        else
      printf("The door cannot be opened.\n");
    }
    return 0;
}

 

0 0
原创粉丝点击