一笔画问题
时间限制:
3000 ms | 内存限制:
65535 KB
难度:
4
-
描述
-
zyc从小就比较喜欢玩一些小游戏,其中就包括画一笔画,他想请你帮他写一个程序,判断一个图是否能够用一笔画下来。
规定,所有的边都只能画一次,不能重复画。
-
输入
-
第一行只有一个正整数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
-
第一行只有一个正整数N(N<=10)表示测试数据的组数。
对于图来说只有当它是欧拉图或者半欧拉图的时候才可以一笔画完,另外一个图是欧拉图或者半欧拉图的前提是该图是连通图。因此对于这道题来说可以先用搜索(我用的DFS,BFS也可以)或者并查集判断其连通性,如果是联通图,再根据欧拉图或者半欧拉图的顶点的度数关系判断是否可以一笔画完。
代码一:并查集判断图的连通性
#include<iostream>
#include<cstring>
using namespace std;
const int N=2000+10;
int d[N],p[N];
int find(int x)
{
if(x==p[x])
return x;
return p[x]=find(p[x]);//压缩路径
}
int main()
{
int t;
cin>>t;
while(t--)
{
memset(d,0,sizeof(d));
int n,m,x,y;
cin>>n>>m;
int i,j;
for(i = 1;i <= n;i ++)//初始化并查集
p[i]=i;
for(i = 1;i <= m;i ++)
{
cin>>x>>y;
d[x]++;
d[y]++;
x=find(x),y=find(y);
if(x!=y)
p[x]=y;
}
int ok=0,jidu=0;//判断是否为连通图及奇度顶点的个数,ok==1为连通图;
for(i=1;i<=n;i++)
{
if(p[i]==i)
ok++;
if(d[i]%2)
jidu++;
}
if(ok==1)
{
if(jidu==0||jidu==2)//连通图是欧拉图和半欧拉图的条件是:没有奇度顶点和只有两个奇度顶点
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
else
cout<<"No"<<endl;
}
return 0;
}
由于当学并查集,最后连通图的判断条件写的不对,浪费了一下午啊,很是郁闷。。。
-
#include<iostream> #include<cstring> using namespace std; const int N=1000+10; int G[N][N],vis[N]; void dfs(int u, int n) { vis[u]=1; for(int i = 1;i <= n;i ++) { if(G[u][i]&&!vis[i]) { dfs(i,n); } } } int main() { int t; cin>>t; while(t--) { memset(G,0,sizeof(G)); memset(vis,0,sizeof(vis)); int i,j,n,m; cin>>n>>m; for(i=0;i<m;i++) { int x,y; cin>>x>>y; G[x][y]=G[y][x]=1; } dfs(1,n); int ok=1; for(i=1;i<=n;i++) { if(vis[i]==0) ok=0; } int jidu=0; for(i=1;i<=n;i++)//计算每个顶点的度数,第i个顶点的度数等于邻接矩阵第i行的所有值之和 { int sum=0; for(j=1;j<=n;j++) { sum+=G[i][j]; } if(sum%2) jidu++; } if(ok) { if(jidu==0||jidu==2) cout<<"Yes"<<endl; else cout<<"No"<<endl; } else cout<<"No"<<endl; } return 0; }
-
代码二:DFS判断图的连通性