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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值