地址:http://acm.hit.edu.cn/judge/show.php?Proid=1033&Contestid=0
思路:可以把这道题等价地看成有向图中求哈密顿路的问题,每个在单词首尾出现过的字母看作一个节点,每个单词首字母看作节点的出度加1,尾字母看作节点的入度加1,而形成哈密顿路的条件是除了哈密顿路首尾两个节点外,其他节点的出度等于入度,而首节点出度比入度多1,尾节点入度比出度多1。除此之外,还要考虑图的连通性问题,因为不连通的图是无法形成哈密顿路的,使用并查集来判断图是否连通。并查集的内容详情可见:http://www.cppblog.com/amazon/archive/2009/08/15/93457.html
代码如下:

#include <stdio.h>
#include 
<string.h>
#include 
<memory.h>

#define OUT 10

typedef 
struct  
{
    
int parent;
    
int height;
}
Node;

Node 
set[26];
bool visited[26];
int record[26], num_record;

void Init()
{
    
int i;

    
for(i = 0; i < 26; i++)
    
{
        visited[i] 
= false;
        
set[i].parent = i;
        
set[i].height = 1;
    }

    num_record 
= 0;
}


int Find(int x)
{
    
while(x != set[x].parent)
    
{
        x 
= set[x].parent;
    }


    
return x;
}


void Merge(int x, int y)
{
    
if(x == y)
    
{
        
return;
    }

    
if(set[x].height == set[y].height)
    
{
        
set[y].parent = x;
        
set[x].height++;
    }

    
else if(set[x].height > set[y].height)
        
set[y].parent = x;
    
else
        
set[x].parent = y;
}


int main()
{
    
int T, N;
    
int i, j;
    
char word[1005];
    
int letter[26];
    
int front, behind;
    
int a, b;
    
bool flag;

    scanf(
"%d"&T);

    
for(i = 0; i < T; i++)
    
{
        front 
= behind = 0;
        memset(letter, 
0sizeof(letter));
        Init();

        scanf(
"%d"&N);

        
for(j = 0; j < N; j++)
        
{
            scanf(
"%s", word);
            a 
= word[0- 'a';
            b 
= word[strlen(word) - 1- 'a';
            letter[a]
++;
            letter[b]
--;
            Merge(Find(a), Find(b));
            
if(visited[a] == false)
            
{
                visited[a] 
= true;
                record[num_record
++= a;
            }

            
if(visited[b] == false)
            
{
                visited[b] 
= true;
                record[num_record
++= b;
            }


        }


        flag 
= false;
        a 
= Find(record[0]);
        
for(j = 1; j < num_record; j++)
        
{
            
if(a != Find(record[j]))
            
{
                flag 
= true;
                
break;
            }

        }

        
if(flag == true)
        
{
            printf(
"The door cannot be opened.\n");
            
continue;
        }

        
        
for(j = 0; j < 26; j++)
        
{
            
if(letter[j] > 1 || letter[j] < -1)
            
{
                front 
= behind = OUT;
                
break;
            }

            
else if(letter[j] == 1)
                front
++;
            
else if(letter[j] == -1)
                behind
++;
        }


        
if((front == 1 && behind == 1|| (front == 0 && behind == 0))
        
{
            printf(
"Ordering is possible.\n");
        }

        
else
        
{
            printf(
"The door cannot be opened.\n");
        }

    }


    
return 0;
}