/*请从main开始看*/
/*
SampleInput:
6 8 7
0 5
2 4
2 3
1 2
0 1
3 4
3 5
0 2
1 4
0 0
1 1
2 2
3 3
4 4
5 5
4 2 2
0 1
2 3
2 1
0 0
*/
#include<cstdio>
#include<cstring>
#include<list>
#include<stack>
#include<set>
using namespace std;
const int maxn = 100002;
list<int> point[maxn];///当然,你也可以使用vector实现
set<int> cc[maxn];///cc指连通分量
bool vis[maxn], color[maxn];
int edgeTo[maxn];///dfs出的路径
stack<int> path;
int beg, end, count;
bool isend, hascycle, isTwoColorable;
///复杂度:O(V+E)
///找路,从v到end
void dfs(int v)
{
vis[v] = true;
list<int>::iterator it;
for (it = point[v].begin(); it != point[v].end(); ++it)
{
if (isend)
return;
int w = (int) * it;
if (!vis[w])
{
edgeTo[w] = v;
if (w == end)
{
isend = true;
return;
}
dfs(w);
}
}
}
///找环,从beg到beg
void dfs(int v, int u)
{
vis[v] = true;
list<int>::iterator it;
for (it = point[v].begin(); it != point[v].end(); ++it)
{
if (hascycle)
return;
int w = (int) * it;
if (!vis[w])
{
edgeTo[w] = v;
dfs(w, v);
}
else if (w != u && w == beg)
///该已找到的点不是前一个点(上一层dfs的点)
///说明从该点出发可以沿着另一条路回来,所以G有环。
{
edgeTo[w] = v;
hascycle = true;
return;
}
}
}
///简单找环
void simpledfs(int v, int u)
{
vis[v] = true;
list<int>::iterator it;
for (it = point[v].begin(); it != point[v].end(); ++it)
{
if (hascycle)
return;
int w = (int) * it;
if (!vis[w])
dfs(w, v);
else if (w != u)
///该已找到的点不是前一个点(上一层dfs的点)
///说明从该点出发可以沿着另一条路回来,所以G有环。
{
hascycle = true;
return;
}
}
}
///双色否
void colordfs(int v)
{
vis[v] = true;
list<int>::iterator it;
for (it = point[v].begin(); it != point[v].end(); ++it)
{
if (!isTwoColorable)
return;
int w = (int) * it;
if (!vis[w])
{
color[w] = !color[v];
colordfs(w);
}
else if (color[w] == color[v])
{
isTwoColorable = false;
return;
}
}
}
///找连通分量,遍历型
void exdfs(int v)
{
vis[v] = true;
cc[count].insert(v);
list<int>::iterator it;
for (it = point[v].begin(); it != point[v].end(); ++it)
{
int w = (int) * it;
if (!vis[w])
exdfs(w);
}
}
///应用1
///输出起点v到终点w的路径,以空格隔开
///如果不存在,则输出-1
inline void printpath(int v, int w)
{
memset(vis, 0, sizeof(vis));
memset(edgeTo, -1, sizeof(edgeTo));
isend = false;
while (!path.empty())
path.pop();
if (v != w)
{
end = w;
dfs(v);
for (int x = w; x != v; x = edgeTo[x])///先从w到v
{
if (~edgeTo[x]) /// edgeTo[x] != -1
path.push(x);
else ///说明v,w在两个不同的连通分量上
{
printf("-1\n");
return;
}
}
printf("%d", v);
while (!path.empty())
{
printf(" %d", path.top());
path.pop();
}
printf("\n");
}
else///找一个环
{
hascycle = false;
beg = v;
dfs(v, v);
if (hascycle)
{
for (int x = edgeTo[v] ; x != v; x = edgeTo[x])
path.push(x);
printf("%d", v);
while (!path.empty())
{
printf(" %d", path.top());
path.pop();
}
printf(" %d\n", v);
}
else
printf("-1\n");
}
}
///应用2
///判断是否为无环图(假设不存在自环或平行边)
inline void hasCycle(int n)
{
memset(vis, 0, sizeof(vis));
hascycle = false;
for (int i = 0; i < n; ++i)
if (!vis[i])
simpledfs(i, i);
}
///应用3
///返回连通子图的个数
inline int count_connected_subgraph(int n)
{
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= count; ++i)
cc[i].clear();
count = 1;
for (int i = 0; i < n; ++i)
{
if (!vis[i])
{
exdfs(i);
++count;
}
}
return count - 1;
}
///应用4
///判断G是否为二分图
inline void checkTwoColor(int n)
{
memset(vis, 0, sizeof(vis));
memset(color, 0, sizeof(color));
isTwoColorable = true;
for (int i = 0; i < n; ++i)
if (!vis[i])
colordfs(i);
}
int main(void)
{
int n, m, k, temp, v, w;///点数=n,边数=m,查询数=k
while (~scanf("%d%d%d", &n, &m, &k))
{
///0. 初始化
temp = m;
while (temp--)
{
scanf("%d%d", &v, &w);///这里输入要求为0~(n-1)
point[v].push_front(w);
point[w].push_front(v);
}
///1. 判断图G是否有环
hasCycle(n);
printf(hascycle ? "YES\n" : "NO\n");
///2. 判断图G是否为二分图
checkTwoColor(n);
printf(isTwoColorable ? "YES\n" : "NO\n");
///3. 连通子图的个数及每个连通子图所包含的点(升序输出)
printf("%d\n", count_connected_subgraph(n));
for (int i = 1; i < count; ++i)
{
set<int>::iterator it;
for (it = cc[i].begin(); it != cc[i].end(); ++it)
printf("%d ", *it);
printf("\n");
}
///4. 判断是否存在v到w的路径/求v到w的路径(保证v,w在范围内)
while (k--)
{
scanf("%d%d", &v, &w);
printpath(v, w);
}
///0. 初始化
for (int i = 0; i < n; ++i)
point[i].clear();
printf("\n");
}
return 0;
}
待实现:欧拉回路