版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/84501069
一笔画问题(欧拉路)
DFS版
/*1.一笔画问题
*规定 所有的边都只能画一次,不能重复画
*输入
第一行只有一个正整数N(N<=10)表示测试数据的组数.
每组测试数据的第一行有两个正整数P,Q(P<=1000,Q<=2000),
分别表示这个画中有多少个顶点和多少条连线.
(点的编号从1到P) 随后的Q行,每行有两个正整数A,B(0 < A,B < P),
表示编号为A和B的两点之间有连线.
*输出
如果存在符合条件的连线,则输出"Yes",
如果不存在符合条件的连线,输出"No".
*样例输入
2
4 3
1 2
1 3
1 4
4 5
1 2
2 3
1 3
1 4
3 4
*样例输出
No
Yes
*/
//DFS version:
#include<bits/stdc++.h>
#define _ 1002
using namespace std;
inline int read()
{
int f=1,num=0;
char ch=getchar();
while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
while (ch>='0'&&ch<='9') num=(num<<1)+(num<<3)+ch-'0',ch=getchar();
return num*f;
}
vector<int> graph[_];
int n,m,cnt,odd;
bool v[_];
void dfs(int x)
{
for(int i=0,y;i<graph[x].size();i++)
if(!v[y=graph[x][i]])
{
cnt++;
if(graph[y].size()%2) odd++;
v[y]=true;
dfs(y);
}
}
int main()
{
int t=read();
while (t--)
{
n=read(),m=read();
for(int i=0;i<=n;i++)
graph[i].clear();
for(int i=0;i<m;i++)
{
int x=read(),y=read();
graph[x].push_back(y);
graph[y].push_back(x);
}
cnt=0,odd=0;
memset(v,false,sizeof(v));
dfs(1);
if((m==0&&n==1)||(cnt==n&&(odd==0||odd==2))) printf("Yes\n");
else printf("No\n");
}
return 0;
}
并查集版
/*1.一笔画问题
*规定 所有的边都只能画一次,不能重复画
*输入
第一行只有一个正整数N(N<=10)表示测试数据的组数.
每组测试数据的第一行有两个正整数P,Q(P<=1000,Q<=2000),
分别表示这个画中有多少个顶点和多少条连线.
(点的编号从1到P) 随后的Q行,每行有两个正整数A,B(0 < A,B < P),
表示编号为A和B的两点之间有连线.
*输出
如果存在符合条件的连线,则输出"Yes",
如果不存在符合条件的连线,输出"No".
*样例输入
2
4 3
1 2
1 3
1 4
4 5
1 2
2 3
1 3
1 4
3 4
*样例输出
No
Yes
*/
//并查集方法
#include<bits/stdc++.h>
#define _ 1005
using namespace std;
inline int read()
{
int f=1,num=0;
char ch=getchar();
while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
while (ch>='0'&&ch<='9') num=(num<<1)+(num<<3)+ch-'0',ch=getchar();
return num*f;
}
int degree[_];//度
int fa[_];
int get(int x)
{
if(x==fa[x]) return x;
return fa[x]=get(fa[x]);
}
int main()
{
int t=read();
while(t--)
{
memset(degree,0,sizeof(degree));
for(int i=0;i<_;++i)
fa[i]=i;
int n=read(),m=read();
for(int i=1;i<=m;++i)
{
int x=read(),y=read();
degree[x]++;
degree[y]++;
int rx=get(x);
int ry=get(y);
fa[ry]=rx;
}
int root=get(1),cnt=0,odd=0;
for(int i=1;i<=n;++i)
{
if(get(i)!=root)
cnt++;
if(degree[i]%2)//度为奇数
odd++;//odd 奇数
}
if(!cnt&&(odd==0||odd==2)) printf("Yes\n");
else printf("No\n");
}
return 0;
}
欧拉路
https://www.luogu.org/problemnew/show/P2731
#include<bits/stdc++.h>
#define _ 1025
using namespace std;
inline int read()
{
int f=1,num=0;
char ch=getchar();
while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
while (ch>='0'&&ch<='9') num=(num<<1)+(num<<3)+ch-'0', ch=getchar();
return num*f;
}
int G[_][_],degree[_];
int n,m;
stack<int>s;//用一个栈来保存路径
void dfs(int x)
{
for (int i=1;i<=n;++i)
if (G[x][i])
{
G[x][i]--;
G[i][x]--;//防止重复走同一边
dfs(i);
}
s.push(x);
}
int main()
{
m=read();
for (int i=1;i<=m;++i)
{
int x=read(),y=read();
n=max(n,x),n=max(n,y);
G[x][y]++,G[y][x]++;
degree[x]++,degree[y]++;
}//用邻接矩阵存图
int u=1;
for (int i=1;i<=n;++i)
if (degree[i]%2)
{
u=i;//起点
break;
}
dfs(u);
while (!s.empty())
{
printf("%d\n",s.top());//倒序输出
s.pop();
}
return 0;
}
构建邻接表
/*
*构建邻接表模板
*/
#include<stdio.h>
#include<string.h>
int head[100100];//表头,head[i]代表起点是i的边的编号
int cnt;//代表边的编号
struct s
{
int u;//记录边的起点
int v;//记录边的终点
int w;//记录边的权值
int next;//指向上一条边的编号
}edge[100010];
void add(int u,int v,int w)//向所要连接的表中加入边
{
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
int i;
cnt=0;
memset(head,-1,sizeof(head));//清空表头数组
for(i=0;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
int u,v,w;
scanf("%d",&u);
for(i=head[u];i!=-1;i=edge[i].next)//输出所有与起点为u相连的边的终点和权值
{
v=edge[i].v;
w=edge[i].w;
printf("%d %d\n",v,w);
}
}
return 0;
}