1. 程式人生 > >UVa 10129 單詞(DFS判斷連通性)

UVa 10129 單詞(DFS判斷連通性)

題意:輸入N個單詞,N < 100000,是否可以把所有這些單詞排成一列,使得每個單詞的第一個字母和最後一個字母相同。每個單詞最多有1000個字母,輸入可能有重複的單詞。

思路: 1、把字母當成結點,單詞看做有向邊,問題有解當且僅當圖中存在歐拉回路。有向圖判斷存在歐拉回路的條件有兩個:(1)把圖看做無向圖,圖是連通的(DFS訪問,若存在未訪問的,則是不連通的) ;(2)最多有兩個點入度不等於出度,其中一個是起點,一個是終點。

2、每行輸入的資料只需記錄首字母和最後一個字母,然後轉化為數字,因此陣列只需開到26記錄26個字母對應的數字即可。

程式碼如下:

#include<cstdio>
#include<cstring>
const int maxn = 1000 + 10;
int G[27][27],in[27],out[27],N,num[27];

void read() //讀入資料
{
	memset(G,0,sizeof(G));
	memset(in,0,sizeof(in));
	memset(out,0,sizeof(out));
	scanf("%d",&N);
	char s[maxn];
	int first,last;
	while(N--)
	{
		scanf("%s",s);
		first = s[0] - 'a';
		last = s[strlen(s)-1] - 'a';
		G[first][last]++;
		in[last]++;
		out[first]++;
	}
	
}

void dfs(int i)
{
	num[i] = 1;
	for(int j = 0;j < 26;j++)
	{
		if((G[i][j] > 0 || G[j][i] > 0) && num[j] == 0)
		{
			dfs(j);
		}
	}
	return;
}

bool judge_connect() //判斷連通性
{
	memset(num,0,sizeof(num));//儲存訪問情況
	for(int i = 0;i < 26;i++)
	{
		if(out[i] > 0)
		{
			dfs(i);
			break;
		}
	}
	
	for(int i = 0;i < 26;i++)
	{
		if((in[i] > 0 || out[i] > 0) && num[i] == 0)
		{
			return false;
		}
	}
	return true;	
}

bool judge_deg() //判斷度數情況
{
	int i,start = 0,end = 0;
	for(i = 0;i < 26;i++)
	{
		if(in[i] != out[i])
		{
			if(in[i] == out[i] + 1)	end++;
			else if(out[i] = in[i] + 1) start++;
			else
			{
				return false;
			}
		}
		if(end > 1 || start > 1)
		{
			return false;
		}
	}
	if(start + end > 2) 
	{
		return false;
	}
	
	return true;
}

int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		read();
		if(judge_connect() && judge_deg())
		{
			printf("Ordering is possible.\n");
		}
		else
		{
			printf("The door cannot be opened.\n");
		}
	}
}