uva10129

题目描述:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19492

/*1:通常想法是将每个单词看成一个节点,但如果单词的尾部与另外一个单词的首部相同,就能架起一座“桥”,但这样以来,数组就开太大了 2:将每个单词的首尾两个字母看成节点,此时单词就是一座桥。这样就可以根据欧拉道路的出入度来判断 3:注意题中判断欧拉道路的起点以及终点的技巧*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>

using namespace std;
const int maxc = 1000 + 5;

int n, in[30], out[30], graph[30][30], start, visit[30];    //从start这个点开始dfs

void dfs(int u) {
    visit[u] = 1;
    for(int v = 0; v < 26; v++) {
        if(graph[u][v] > 0) {   //因为节点可以重复,所以不能在条件里加上 && !visit[v]
            graph[u][v]--;      graph[v][u]--;
            dfs(v);
        }
    }
}

bool isConnected() {
    memset(visit, 0, sizeof(visit));
    dfs(start);
    for(int i = 0; i < 26; i++)
        if(in[i] + out[i])  //出入度为0的字母没有出现过,此时不计
            if(!visit[i])   return false;
    return true;
}

bool solve() {
    if(!isConnected())  return false;

    int theBegin = 0, theEnd = 0;
    for(int u = 0; u < 26; u++) {
        if(in[u] != out[u]) {
            if(!theBegin && out[u] - in[u] == 1)    theBegin = 1;
            else if(!theEnd && in[u] - out[u] == 1)     theEnd = 1;
            else return false;
        }
    }
    return true;
}

int main() {
    int kase;
    scanf("%d", &kase);
    while(kase--) {
        scanf("%d", &n);

        //初始化
        memset(in, 0, sizeof(in));
        memset(out, 0, sizeof(out));
        memset(graph, 0, sizeof(graph));

        //输入同时确定出度以及入度
        string str;
        for(int i = 0; i < n; i++) {
            cin >> str;
            int u = str[0] - 'a';   int v = str[str.length() - 1] - 'a';
            out[u]++;   in[v]++;
            graph[u][v]++;  graph[v][u]++;//注意虽然是有向图,但这行代码这样写的目地是为了dfs能够顺利遍历整张图,不然有些点访问不到
            start = u;
        }

        if(solve())     printf("Ordering is possible.\n");
        else              printf("The door cannot be opened.\n");
    }
}

你可能感兴趣的:(uva10129)