NYOJ-42 一笔画问题(图论,深搜)

一笔画问题

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


你可能感兴趣的:(图论,深搜)