您的位置:首页 > 编程语言 > Java开发

nyoj42 一笔画问题(欧拉回路+并查集)

2017-10-29 11:19 260 查看


一笔画问题

时间限制: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

先来介绍一下关于欧拉回路判定定理的知识点

定理以及推论:
无向图G 存在欧拉通路的充要条件是:

G 为连通图,并且G 仅有两个奇度结点(度数为奇数的顶点)或者无奇度结点。

推论5.1:

1) 当G 是仅有两个奇度结点的连通图时,G 的欧拉通路必以此两个结点为端点。

2) 当G 是无奇度结点的连通图时,G 必有欧拉回路。

3) G 为欧拉图(存在欧拉回路)的充分必要条件是G 为无奇度结点的连通图。

定理5.2

有向图D 存在欧拉通路的充要条件是:

D 为有向图,D 的基图连通,并且所有顶点的出度与入度都相等;或者除两个顶点外,其余

顶点的出度与入度都相等,而这两个顶点中一个顶点的出度与入度之差为1,另一个顶点的出度

与入度之差为-1。

推论5.2:

1) 当D 除出、入度之差为1,-1 的两个顶点之外,其余顶点的出度与入度都相等时,D 的

有向欧拉通路必以出、入度之差为1 的顶点作为始点,以出、入度之差为-1 的顶点作为

终点。

2) 当D 的所有顶点的出、入度都相等时,D 中存在有向欧拉回路。

3) 有向图D 为有向欧拉图的充分必要条件是D 的基图为连通图,并且所有顶点的出、入度

都相等。

看了上面的理论会发现这个题目很好理解 关于理论不懂得地方 自己可以手动画一下图就会一目了然了

关于并查集的介绍 :http://blog.csdn.net/qq_33913037/article/details/71124106

了解了上面的知识过后 来分析下这个题目 
关于图的连通性用并查集来判断 当一个节点的父节点还是本身的话证明这个图不连通
判断图的连通性过后 根据出度和入度去判定是否存在欧拉回路

java代码 这个题目没用到并查集 不过也可以使用并查集去判断连通性
package bfs;

import java.util.Arrays;
import java.util.Scanner;

/**
*
*/
public class Main42 {
static int p,q;
static int a[][]=new int[1000+10][1000+10];
static int pd[]=new int[1000+10];
static boolean vis[]=new boolean[1000+10];
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int t=scanner.nextInt();
while (t-->0){
p=scanner.nextInt();
q=scanner.nextInt();
init();
Arrays.fill(pd,0);
for (int i=0;i<q;i++){
int u=scanner.nextInt();
int v=scanner.nextInt();
a[u][v]=1;
a[v][u]=1;
pd[u]++;
pd[v]++;
}
//判断是否是连通图
Arrays.fill(vis,false);
dfs(1);
boolean flag=true;
for (int i=1;i<=p;i++){
if (!vis[i]){
flag=false;
break;
}
}
int sum=0;
for (int i=1;i<=p;i++){
if (pd[i]%2==1){
sum++;
}
}
if(sum!=0&&sum!=2){
flag = false;
}
if(flag)
System.out.println("Yes");
else System.out.println("No");
}
}

private static void dfs(int s) {
vis[s]=true;
for (int i=0;i<=p;i++){
if (i!=s&&a[s][i]==1&&!vis[i]){
dfs(i);
}
}
}

private static void init() {
for (int i=0;i<1000+10;i++){
for (int j=0;j<1000+10;j++){
a[i][j]=0;
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息