您的位置:首页 > 其它

uva 10129 Play On Words(并查集法和DFS法)

2015-08-11 09:15 351 查看
原题链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1070
考查有向图的欧拉路。

判断条件:

1.忽略边的方向后图连通。

2.出度==入度 +(一个 顶点出度+1==入度,一个顶点 入度+1==出度) 这两个顶点可有可无

判断图连通方法:

1.并查集法

说白了就是建一个与结点数相等的数组,里面存对应结点的上一个结点。因此,可以通过该数组找到根节点。

通过判断根节点是否相同来判断图是否连通。

2.DFS法

DFS一遍后,如果所有节点遍历到,则图连通;否则,不连通。

a.可直接利用G图判断是否有没遍历到的边。

b.可建一个辅助数组vis,记录该点是否遍历到。

详见代码:

并查集法:

#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int indegree[30], outdegree[30],pre[30];//分别记录:入度、出度、该结点的前一个结点
int find(int x)
{
int p = x;
while (pre[p] != p)
p = pre[p];
//下面这个循环可不写。  并查集的路径压缩
int i = x, j;
while (pre[i] != p)
{
j = pre[i];
pre[i] = p;
i = j;
}
return p;
}
int main()
{
int T;
cin >> T;
while (T--)
{
string str;
int n,begin,end,root;
memset(indegree, 0, sizeof(indegree));
memset(outdegree, 0, sizeof(outdegree));
for (int i = 0; i < 30; i++)	//勿忘初始化
pre[i] = i;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> str;
begin = str[0] - 'a';
end = str[str.length() - 1] - 'a';
outdegree[begin]++;
indegree[end]++;
pre[find(begin)] = find(end);	//将根结点相连接,更新根结点
root = find(end);	//root记录根结点,不断更新,直到最根本的那个结点
}
bool p = false;
int sumin = 0,sumout=0;
for (int i = 0; i < 26; i++)
{
if (indegree[i] || outdegree[i])
{
if (find(i) != root)		//如果该结点的根节点与root不一样,说明图不连通
p = true;
if (indegree[i] == outdegree[i])
continue;
if (indegree[i] + 1 == outdegree[i])
sumout++;
else if (indegree[i] == outdegree[i] + 1)
sumin++;
else p = true;		//属 |入度 - 出度|>=2  的情况
if (p || sumin >= 2 || sumout >= 2)
break;
}
}
if (p || sumin >= 2 || sumout >= 2)
cout << "The door cannot be opened." << endl;
else
cout << "Ordering is possible." << endl;
}
return 0;
}


DFS法:

注释部分为用辅助数组vis的方法。

#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int G[27][27], indegree[30], outdegree[30];
//bool vis[30];
void DFS(int u)
{
//vis[u] = true;		//标记遍历过该点
for (int v = 0; v < 26; v++)
{
if (G[u][v])
{
G[u][v]--;
G[v][u]--;	//别忘是判断无向图的连通性
DFS(v);
}
}
}
int main()
{
int T;
cin >> T;
while (T--)
{
string str;
int n;
int begin, end;
memset(indegree, 0, sizeof(indegree));
memset(outdegree, 0, sizeof(outdegree));
memset(G, 0, sizeof(G));
//memset(vis, 0, sizeof(vis));
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> str;
begin = str[0] - 'a';
end = str[str.length() - 1] - 'a';
outdegree[end]++;
indegree[begin]++;
G[begin][end]++;
G[end][begin]++;
}
DFS(0);
int sumin = 0, sumout = 0;
bool boss = false;
for (int i = 0; i < 26; i++)
{
for (int j = 0; j < 26;j++)	//判断是否有没遍历到的边
if (G[i][j])
{
boss = true; break;
}
if (indegree[i] || outdegree[i])
{
/*if (vis[i] == false)	//判断是否有没遍历到的点
{
boss = true;
break;
}*/
if (indegree[i] == outdegree[i])
continue;
if (indegree[i] + 1 == outdegree[i])
sumout++;
else if (indegree[i] == outdegree[i] + 1)
sumin++;
else		//属 |入度 - 出度|>=2  的情况
{
boss = true; break;
}
if (boss || sumin >= 2 || sumout >= 2)
break;
}
}
if (boss || sumin >= 2 || sumout >= 2)
cout << "The door cannot be opened." << endl;
else
cout << "Ordering is possible." << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: