目录
1126 Eulerian Path
题目描述
解题思路
程序
vector中resize和reserve函数的区别
参考博客
In graph theory, an Eulerian path is a path in a graph which visits every edge exactly once. Similarly, an Eulerian circuit is an Eulerian path which starts and ends on the same vertex. They were first discussed by Leonhard Euler while solving the famous Seven Bridges of Konigsberg problem in 1736. It has been proven that connected graphs with all vertices of even degree have an Eulerian circuit, and such graphs are called Eulerian. If there are exactly two vertices of odd degree, all Eulerian paths start at one of them and end at the other. A graph that has an Eulerian path but not an Eulerian circuit is called semi-Eulerian. (Cited from https://en.wikipedia.org/wiki/Eulerian_path)
Given an undirected graph, you are supposed to tell if it is Eulerian, semi-Eulerian, or non-Eulerian.
Each input file contains one test case. Each case starts with a line containing 2 numbers N (≤ 500), and M, which are the total number of vertices, and the number of edges, respectively. Then M lines follow, each describes an edge by giving the two ends of the edge (the vertices are numbered from 1 to N).
For each test case, first print in a line the degrees of the vertices in ascending order of their indices. Then in the next line print your conclusion about the graph -- either Eulerian
, Semi-Eulerian
, or Non-Eulerian
. Note that all the numbers in the first line must be separated by exactly 1 space, and there must be no extra space at the beginning or the end of the line.
7 12
5 7
1 2
1 3
2 3
2 4
3 4
5 2
7 6
6 3
4 5
6 4
5 6
2 4 4 4 4 4 2
Eulerian
6 10
1 2
1 3
2 3
2 4
3 4
5 2
6 3
4 5
6 4
5 6
2 4 4 4 3 3
Semi-Eulerian
5 8
1 2
2 5
5 4
4 1
1 3
3 2
3 4
5 3
3 3 4 3 3
Non-Eulerian
欧拉图和半欧拉图:首先确定图必须为连通图
若图G中存在这样一条路径,使得它恰好通过G中的每条边一次,则称该路径为欧拉路径。若该路径为一条回路,则成为欧拉回路。具有欧拉回路的图成为欧拉图,具有欧拉路径,但不具有欧拉回路的图成为半欧拉图
对于无向连通图来说,度数为奇数的点的个数为0,则为欧拉图,度数为奇数的点的个数为2个,则为半欧拉图
对于有向连通图来说,当且仅当每个节点的入度等于出度,则为欧拉图
当且仅当除了两个节点外,其余节点的入度等于出度,且此两节点满足起点s的入度=出度-1,结束点t的出度=入度-1,则为半欧拉图
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 550;
int degree[maxn],n,m,flag[maxn],cnt;
vector> grep;
void dfs(int pos)
{
flag[pos] = 1;
cnt++;
for(int it : grep[pos])
if(!flag[it])
dfs(it);
}
int main()
{
int x,y;
scanf("%d%d",&n,&m);
grep.resize(n+1);
for(int i =0 ;i < m;i ++)
{
scanf("%d%d",&x,&y);
degree[x] ++;degree[y]++;
grep[x].push_back(y);
grep[y].push_back(x);
}
int num = 0;
bool flag = true;
for(int i = 1;i <= n;i ++)
{
printf("%d%c",degree[i],i==n?'\n':' ');
if(degree[i] % 2 == 1)
num++;
}
dfs(1);
if(num == 0 && cnt == n)
printf("Eulerian\n");
else if(num == 2 && cnt == n)
printf("Semi-Eulerian\n");
else
printf("Non-Eulerian\n");
return 0;
}
resize是改变的size,而reserve改变的是capacity
resize的源程序为:
iterator erase(iterator first, iterator last) { //释放某个区间 释放区间的[first,last)
iterator i = copy(last, finish, first); //首先将后面区域的元素移到前面
destroy(i, finish); //析构掉相应后面的对象
finish = finish - (last - first); //更新区间结束指针
return first;
}
void resize(size_type new_size, const T& x) {
if (new_size < size()) //新空间小于现在的空间
erase(begin() + new_size, end());
else
insert(end(), new_size - size(), x); //否则在end后面插入new_size-size()大小的空间,当然resize也可能是capacity发生改变
}
void resize(size_type new_size) { resize(new_size, T()); }
reserve的源程序为:
void reserve(size_type n) { //如果当前内存大小小于n(包含未用的),那么新开辟一个空间,将所有元素存放到新的内存
if (capacity() < n) {
const size_type old_size = size(); //现在拥有的长度
iterator tmp = allocate_and_copy(n, start, finish); //开辟长度为n的空间,并且将strat到finish的内容重新拷贝到其中
destroy(start, finish); //销毁原来的对象
deallocate(); //销毁原始内存区域
start = tmp;
finish = tmp + old_size;
end_of_storage = start + n;
}
}
欧拉图和半欧拉图