您的位置:首页 > 其它

有向图的欧拉路径POJ2337

2015-10-24 09:50 260 查看
每个单词可以看做一条边,每个字母就是顶点。

有向图欧拉回路的判定,首先判断入度和出度,其实这个题判定的是欧拉通路,不一定非得构成环,所以可以有一个点的顶点入度比出度大1,另外一个点的出度比入度大1,或者每个点的出度和入度相等。用并查集判断是否弱联通。最后dfs求出欧拉路径,不过这个题是让求字典序最小的那个,所以加边之前先把边排序。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
const int maxn = 1100;
struct Edge {
int to, next;
int id;
}edge[maxn * 2];
int tot, head[maxn];
int in[maxn], out[maxn];
int F[maxn];
int st;
bool vis[30];
string str[maxn];
void init()
{
tot = 0;
memset(head, -1, sizeof(head));
memset(F, -1, sizeof(F));
}
void addedge(int u, int v, int id)
{
edge[tot].to = v;
edge[tot].next = head[u];
edge[tot].id = id;
head[u] = tot++;
}
int Find(int x)
{
if (F[x] == -1) return x;
return F[x] = Find(F[x]);
}
void Union(int x, int y)
{
int tx = Find(x);
int ty = Find(y);
if (tx != ty)
F[tx] = ty;
}
bool check(int s)
{
int in1 = 0, out1 = 0;
for (int i = 1; i <= 26; i++)//判断出入度关系
{
if (in[i] == out[i]) continue;
else if (in[i] - out[i] == 1) in1++;
else if (out[i] - in[i] == 1) out1++, st = i;//如果有出度比入度大1的,说明是欧拉通路,起点只能是那个出度比入度大1的那个点
else return false;
}
//printf("in1 = %d, out1 = %d\n", in1, out1);
if (!(in1 == 1 && out1 == 1) && !(in1 == 0 && out1 == 0)) return false;
for (int i = 1; i <= 26; i++)//判断弱联通
if (vis[i] && Find(i) != Find(s))
return false;
return true;
}
bool vis2[maxn * 2];//判断每条边是否访问过。
int top;
int ans[maxn * 2];//保存路径
void dfs(int u)
{
for (int i = head[u]; i != -1; i = edge[i].next)
{
if (!vis2[i])
{
vis2[i] = true;
dfs(edge[i].to);
ans[top++] = i;
}
}
}
int main()
{
int T, n;
scanf("%d", &T);
while (T--)
{
init();
scanf("%d", &n);
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
memset(vis, false, sizeof(vis));
int u, v;
st = 10000;
for (int i = 0; i <n; i++)
cin >> str[i];
sort(str, str + n);//从小到大排序
for (int i = n - 1; i >= 0; i--)//因为链式前向星是逆序存图,所以反过来从大到小读入。
{
u = str[i][0] - 'a' + 1;
v = str[i][str[i].length() - 1] - 'a' + 1;
vis[u] = vis[v] = true;
addedge(u, v, i);
++in[v];
++out[u];
Union(u, v);
st = min(st, min(u, v));//找出最小的那个点来
}
if (!check(st))
puts("***");
else
{
top = 0;
memset(vis2, false, sizeof(vis2));
dfs(st);
for (int i = top - 1; i > 0; i--)
cout << str[edge[ans[i]].id] << ".";
cout << str[edge[ans[0]].id] << endl;
}

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: