一笔画问题

来源:互联网 发布:怎样修改软件版本号 编辑:程序博客网 时间:2024/04/29 18:35

一笔画问题

时间限制: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"。
样例输入
24 31 21 31 44 51 22 31 31 43 4
样例输出
NoYes
来源
[张云聪]原创
上传者

张云聪



[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 思路:无向图中存在欧拉路径的充要条件:第一,图是连通的,第二,图中顶点的度数都为偶数或者只有两个为奇数。  

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 有向图中存在欧拉路径的充要条件是每个点的入度等于出度。每个点进去多少次就出来多少次。  

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 图连通的判定要用深搜,搜完一遍之后若是有未访问的节点则说明不连通。注意没有度为0的节点图也不一定连通。  



方法1:

自己建立的邻接表;用深搜如果能够经过所有边和点则能用一笔画画下来;




 
 
#include<stdio.h>
#include<stdlib.h>
#include<string.h>


typedef struct node
{
int data;
struct node *next;
}Node;


typedef struct map
{
int city;
int in;
Node *firstedge;
}Map;


bool visited[2000][2000];
int C, E, En, count;//C代表城市的数目,E代表边的条数;
Map M[2000];
bool flag, f;
void dfs(int i, int n);
void destroy();


int main()
{
int i, N,A, B;
Node *p;
scanf("%d", &N);
while(N--)
{
flag = 0;
                f = 0;
count = 0;
memset(M, 0, sizeof(M));
memset(visited, 0, sizeof(visited));
scanf("%d%d", &C, &E);
for(i = 1; i <= C; i++)//初始化
{
M[i].city = i;
M[i].firstedge = NULL;
}
En = E;
while(En--)//建立邻接表
{
scanf("%d%d", &A, &B);
p = (Node *)malloc(sizeof(Node));
p -> data = B;
M[A].in++;
M[B].in++;
p -> next = M[A].firstedge;
M[A].firstedge = p;
p = (Node *)malloc(sizeof(Node));
p->data = A;
p->next = M[B].firstedge;
M[B].firstedge = p;
}
for(i = 1; i <= C; i++)
{
if(M[i].in == 0)//如果存在入度为0的点说明有一个孤立点,不连通
{
f = 1;
printf("No\n");
break;
}
}
if(f == 0)
{
for(i = 1; i <= C; i++)
{
dfs(i,0);
if(flag == 1)
break;
}
if(flag == 0)
printf("No\n");
}
destroy();

}
return 0;
}


void destroy()
{
int i;
Node *p, *q;
for(i = 1; i <= C; i++)
{
p = M[i].firstedge;
while(p)
{
q = p->next;
free(p);
p = q;
}
}
}
void dfs(int i, int n)
{
Node *e;
int j;
if(flag == 1)
return ;
if(n == E)
{
flag = 1;
printf("Yes\n");
return;
}
else
{
e = (Node *)malloc(sizeof(Node));
e = M[i].firstedge;
j = i;
if(e)
{
while(e)
{
if(!visited[e->data][j])
{
visited[j][e->data] = visited[e->data][j] = 1;
dfs(e->data, n+1);
if(flag == 1)
return;
visited[j][e->data] = visited[e->data][j] = 0;
}
e = e->next;
}

}
}
}                



方法2:

运用欧拉定理,先判断图是否连通,再看度的奇偶点的数目


 
 
#include<stdio.h>
#include<stdlib.h>
#include<string.h>


typedef struct node
{
int data;
struct node *next;
}Node;


typedef struct map
{
int city;
int in;
Node *firstedge;
}Map;


bool visited[2000];
int C, E, En, count[2], n = 1;
Map M[2000];
bool flag;
void dfs(int i);
void destroy();


int main()
{
int i, N,A, B;//c¡À¨ª¨º?3?¨ºD¦Ì?¨ºy??¡ê? E¡À¨ª¨º?¡À?¦Ì?¨¬?¨ºy;
Node *p;
scanf("%d", &N);
while(N--)
{
flag = 0;
n = 1;
memset(count, 0, sizeof(count));
memset(M, 0, sizeof(M));
memset(visited, 0, sizeof(visited));
scanf("%d%d", &C, &E);
for(i = 1; i <= C; i++)
{
M[i].city = i;
M[i].firstedge = NULL;
}
En = E;
while(En--)
{
scanf("%d%d", &A, &B);//Ao¨ªB??¨®D¨¢???;
p = (Node *)malloc(sizeof(Node));
p -> data = B;
M[A].in++;
M[B].in++;
p -> next = M[A].firstedge;
M[A].firstedge = p;
p = (Node *)malloc(sizeof(Node));
p->data = A;
p->next = M[B].firstedge;
M[B].firstedge = p;
}
visited[1] = 1;
dfs(1);
if(flag == 1)
{
for(i = 1; i <= C; i++)
{
if(M[i].in % 2 != 0)
{
count[1]++;//奇度点
}
if(M[i].in % 2 == 0)
count[0]++;//偶度点;
}
if((count[1] == 2 && count[0] == C - 2 )||(count[0] == C && count[1] == 0))
printf("Yes\n");
else
printf("No\n");
}
else
printf("No\n");
destroy();

}
return 0;
}


void destroy()
{
int i;
Node *p, *q;
for(i = 1; i <= C; i++)
{
p = M[i].firstedge;
while(p)
{
q = p->next;
free(p);
p = q;
}
}
}
void dfs(int i)
{
Node *e;
int j;
if(flag == 1)
return ;
if(n == C)
{
flag = 1;
return ;
}
else
{
e = (Node *)malloc(sizeof(Node));
e = M[i].firstedge;
while(e)
{
if(!visited[e->data])
{
visited[e->data] = 1;
n++;
dfs(e->data);
}
e = e->next;
}
}
}

方法3:


用容器类《vector》, 不用自己去建邻接表;运用欧拉定理;


#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
#include<vector>


vector<int>g[2000];
bool visited[2000],flag;
int C, E, n = 1;


void dfs(int i)
{
int j;
if(n == C)
{
flag = 1;
return;
}
else
{
for(j = 0; j < g[i].size(); j++)//g[i].size即求得g[i]的后面的链表元素个数,即度;
{
if(!visited[g[i][j]])//g[i][j]即g[i]后的链表的第j个点;
{
visited[g[i][j]] = 1;
n++;
dfs(g[i][j]);
}
}
}
}
void create_map(int e)
{
int i, A,B;
for(i = 0; i < e; i++)
{
scanf("%d%d", &A, &B);
g[A].push_back(B);
g[B].push_back(A);
}
}
void init(int n)
{
int i;
for(i = 1; i <= n; i++)
{
g[i].clear();
}
}




int main()
{
int N, i, degree, num;
scanf("%d", &N);
while(N--)
{
memset(visited, 0, sizeof(visited));
flag = 0; n = 1,num = 0;
scanf("%d%d", &C, &E);
init(C);
create_map(E);
visited[1] = 1;
dfs(1);
for(i = 1; i <= C; i++)
{
degree = g[i].size();
if(degree % 2 != 0)//记录奇度点
num++;
}
if(flag &&(num == 2 || num == 0))
{
printf("Yes\n");
}
else
{
printf("No\n");
}
}
return 0;
}




0 0
原创粉丝点击