uva10129 Play On words (有向歐拉道路存在性)

題意:判斷能不能把所有單詞首尾相連。 能單詞相連的部分字母必須相同

思路:其實就是判斷歐拉道路的存在性。 每個單詞只取首位, 不用保存。  剛看題目以爲是拓撲排序。 有點混亂了。

   方法一:用並查集判斷圖的連通性(判斷連通性需要把有向圖當做無向圖來看!)

   方法二:用DFS來判斷圖的連通性。

   以上兩種方法都要判斷度數的合法性: 即 所有vertex 的 in-deg == out-deg,或 有一個點in-deg == out-deg    + 1 且 還有一點 in-deg + 1 == out-deg


算法複雜度:未知


代碼:

DFS版: 最近不知爲何, 歐拉圖一用DFS就錯, 理解得不深又想優化帶來的禍啊。 

      DFS, 每走過一個點, 標記爲走過。 最後判斷是不是所有一開始就有的點都走過。

/*DFS判斷連通*/
#include <cstdio>
#include <cstring>
using namespace std;

#define MAX_V 26
#define MAX_LEN 1005

int G[MAX_V][MAX_V];
int inDeg[MAX_V];
int outDeg[MAX_V];
int vis[MAX_V];

void DFS(int);
bool okDeg();
bool okDFS();

int main()
{
	int cases;
	scanf("%d", &cases);
	while (cases--) {
		// init
		memset(G, 0, sizeof(G));
		memset(inDeg, 0, sizeof(inDeg));
		memset(outDeg, 0, sizeof(outDeg));
		memset(vis, 0, sizeof(vis));
		int edge, star;
		scanf("%d%*c", &edge);

		// enter
		for (int i = 0; i < edge; i++) {
			char str[MAX_LEN];
			gets(str);
			int u = str[0] - 'a';
			int v = str[strlen(str) - 1] - 'a';
			outDeg[u]++;
			inDeg[v]++;
			G[u][v]++;
			G[v][u]++;
			star = u;
		}

		// judge
		DFS(star);
		if (okDeg() && okDFS()) {
			printf("Ordering is possible.\n");
		}else {
			printf("The door cannot be opened.\n");
		}
		
		// end a case

	}
	
	return 0;
}

void DFS(int u)
{
	vis[u] = true;
	for (int i = 0; i < MAX_V; i++) {
		if (G[u][i] > 0) {
			G[u][i]--;
			G[i][u]--;
			DFS(i);
		}
	}
}

bool okDeg()
{
	bool markStar = false;
	bool markEnd = false;

	for (int i = 0; i < MAX_V; i++) {
		if (inDeg[i] != outDeg[i]) {
			if (!markEnd && inDeg[i] == outDeg[i] + 1) {
				markEnd = true;
			}else if (!markStar && inDeg[i] + 1 == outDeg[i]){
				markStar = true;
			}else {
				return false;
			}
		}
	}

	return true;
}
bool okDFS()
{
	for (int u = 0; u < MAX_V; u++) {
		if (inDeg[u] + outDeg[u]) {
			if (vis[u] == false) {
				return false;
			}
		}
	}

	return true;
}


並查集判連通:

每輸入一條邊就連接這兩個點(如果不會形成環的話), 最後統計所有一開始就有的點, 如果父節點就是這點本身那集合數set就++;  set == 1 說明圖連通。 

/*並查集判連通*/
#include <cstdio>
#include <cstring>
using namespace std;

#define MAX_V 26
#define MAX_LEN 1005

int inDeg[MAX_V];
int outDeg[MAX_V];
int father[MAX_V];

int findFathers(int);
int unite(int, int);
bool okDeg();

int main()
{
	int cases;
	scanf("%d", &cases);
	while (cases--) {
		// init
		int edge;
		scanf("%d%*c", &edge);
		memset(inDeg, 0, sizeof(inDeg));
		memset(outDeg, 0, sizeof(outDeg));
		memset(father, 0, sizeof(father));
		for (int i = 0; i < MAX_V; i++) {
			father[i] = i;
		}

		// enter
		for (int i = 0; i < edge; i++) {
			char str[MAX_LEN];
			gets(str);
			int u = str[0] - 'a';
			int v = str[strlen(str) - 1] - 'a';
			inDeg[v]++;
			outDeg[u]++;
			unite(u, v);
		}

		// judge deg
		if (okDeg()) {
			// count set number
			// judge a vertex is a set when the vertex exist
			int set = 0;
			for (int i = 0; i < MAX_V; i++)	 if (inDeg[i]+outDeg[i]) {
				if (father[i] == i) {
					set++;
				}
			}

			//judge set
			if (set > 1) {
				printf("The door cannot be opened.\n");
			}else {
				printf("Ordering is possible.\n");
			}
		}else {
			printf("The door cannot be opened.\n");
		}
	}

	return 0;
}

int findFathers(int x)
{
	if (father[x] != x) {
		father[x] = findFathers(father[x]);
		return father[x];
	}

	return x;
}

int unite(int x, int y)
{
	x = findFathers(x);
	y = findFathers(y);

	if (x != y) {
		father[x] = y;
	}
}

bool okDeg()
{
	bool markStar = false;
	bool markEnd = false;
	
	for (int i = 0; i < MAX_V; i++) {
		if (inDeg[i] != outDeg[i]) {
			if (inDeg[i] + 1 == outDeg[i] && !markStar) {
				markStar = true;
			}else if (inDeg[i] == outDeg[i] + 1 && !markEnd) {
				markEnd = true;
			}else {
				return false;
			}
		}
	}

	return true;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章