一笔画问题
时间限制:
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
来源
- [张云聪]原创 上传者
思路:
1.首先深搜判断图是不是连通的;
2.若是连通的,则判断是不是欧拉图或者半欧拉图;
即检查满足以下条件之一: a。所有节点读书为偶数; b。奇度节点个数<=2;
满足,则输出Yes,否则No;
代码:
#include <stdio.h> #include <string.h> #include <vector> #define N 1010 using namespace std; struct Node{ //临界表建图 vector<int>next; }; int p, q, li; // p顶点数 q连边数 li是list数组长度 Node a[N]; int list[N]; // 记录所有使用过的节点编号 bool bz[N]; // 标记数组 bool dfs(int start); // 深搜,判断图是否连通 bool jc(); // 检查深搜过程中是否遍历到所有节点 int main() { int n; scanf("%d", &n); while(n --){ memset(bz, 0, sizeof(bz)); int x, y; li = 0; scanf("%d%d", &p, &q); for(int i = 0; i < q; i++){ //建图 scanf("%d%d", &x, &y); a[x].next.push_back(y); a[y].next.push_back(x); if(!bz[x]) { list[li++] = x; bz[x] = 1; } if(!bz[y]) { list[li++] = y; bz[y] = 1; } } bz[list[0]] = 0; int t = dfs(list[0]); //深搜判断图是否连通 int ls = 0, js = 0; for(int j = 0; j < li; j ++){ //判断是不是欧拉图,或者半欧拉图 ls = a[list[j]].next.size(); if(ls % 2) js ++; a[list[j]].next.clear(); } if(js > 2) t = 1; if(!t) printf("Yes\n"); else printf("No\n"); } return 0; } bool dfs(int start) { for(int i = 0; i < a[start].next.size(); i ++){ int t = a[start].next.at(i); if(!bz[t]) continue; bz[t] = 0; if(!jc()) return 0; if(!dfs(t)) return 0; bz[t] = 1; } return 1; } bool jc() { for(int i = 0; i < li; i ++){ if(bz[list[i]]) return 1; } return 0; }
-
第一行只有一个正整数N(N<=10)表示测试数据的组数。