NYOJ42

18 篇文章 0 订阅
16 篇文章 0 订阅

一笔画问题

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


欧拉通路: 通过图中每条边且只通过一次,并且经过每一顶点的通路。

欧拉回路: 通过图中每条边且只通过一次,并且经过每一顶点的回路。

 

无向图是否具有欧拉通路或回路的判定:

欧拉通路:图连通;图中只有0个或2个度为奇数的节点

欧拉回路:图连通;图中所有节点度均为偶数

 (欧拉通路包含欧拉回路:当图中只有0个度为奇数时)

有向图是否具有欧拉通路或回路的判定:

欧拉通路:图连通;除2个端点外其余节点入度=出度;1个端点入度比出度大1;一个端点入度比出度小1 或 所有节点入度等于出度

欧拉回路:图连通;所有节点入度等于出度


混合图(有的边是单向的,有的边是无向的。常被用于比喻城市里的交通网络,有的路是单行道,有的路是双行道。)


原来混合图欧拉回路用的是网络流。
  把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。
  好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以2,得x。也就是说,对于每一个点,只要将x条边改变方向(入>出就是变入,出>入就是变出),就能保证出 = 入。如果每个点都是出 = 入,那么很明显,该图就存在欧拉回路。
  现在的问题就变成了:我该改变哪些边,可以让每个点出 = 入?构造网络流模型。首先,有向边是不能改变方向的,要之无用,删。一开始不是把无向边定向了吗?定的是什么向,就把网络构建成什么样,边长容量上限1。另新建s和t。对于入 > 出的点u,连接边(u, t)、容量为x,对于出 > 入的点v,连接边(s, v),容量为x(注意对不同的点x不同)。之后,察看是否有满流的分配。有就是能有欧拉回路,没有就是没有。欧拉回路是哪个?察看流值分配,将所有流量非0(上限是1,流值不是0就是1)的边反向,就能得到每点入度 = 出度的欧拉图。
  由于是满流,所以每个入 > 出的点,都有x条边进来,将这些进来的边反向,OK,入 = 出了。对于出 > 入的点亦然。那么,没和s、t连接的点怎么办?和s连接的条件是出 > 入,和t连接的条件是入 > 出,那么这个既没和s也没和t连接的点,自然早在开始就已经满足入 = 出了。那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡
并查集+欧拉通路
#include<iostream>
#include<cstring>
using namespace std;
int mp[1001],pre[1001];
int find(int x)
{
 int r=x;
 while(pre[r]!=r)
 r=pre[r];
 int i=x,j;
 while(pre[i]!=r)
 {
  j=pre[i];
  pre[i]=r;
  i=j;
 }
 return r;
}
void join(int x,int y)
{
 int fx=find(x),fy=find(y);
 if(fx!=fy)
 pre[fx]=fy;
}
int main()
{
 int n,p,q,a,b;
 cin>>n;
 while(n--)
 {
  cin>>p>>q;
  memset(mp,0,sizeof(mp));
  for(int i=1;i<=p;i++)
  {
   pre[i]=i;
  }
  for(int i=0;i<q;i++)
  {
   cin>>a>>b;
   mp[a]++,mp[b]++;
   join(a,b);
  }
  int count=0,count1=0;
  for(int i=1;i<=p;i++)
  {
  if(pre[i]==i)
  count++;
  if(mp[i]%2)
  count1++;
 }
  if(count==1&&(count1==0||count1==2))
  cout<<"Yes"<<endl;
  else
  {
   cout<<"No"<<endl; 
  }
 }
}
dfs+欧拉通路

#include<iostream>
#include<cstring>
using namespace std;
int pre[1001],N,p,q,a,b;;
bool mp[1001][1001],vis[1001];
void dfs(int x)
{
 vis[x]=true;
 for(int i=1;i<=p;i++)
 {
  if(mp[x][i])
  {
   pre[x]++;
   if(!vis[i])
   dfs(i);
  }
  
 }
}
int main()
{
 cin>>N;
 while(N--)
 {
  cin>>p>>q;
  memset(mp,false,sizeof(mp));
  memset(vis,false,sizeof(vis));
  memset(pre,0,sizeof(pre));
  for(int i=1;i<=q;i++)
  {
   cin>>a>>b;
   mp[a][b]=true,mp[b][a]=true;
  }
  dfs(1);
  int mark=1,count=0;
  for(int i=1;i<=p;i++)
  {
   if(!vis[i])
   {
    mark=0;
    break;
   }
  }
  if(mark)
  {
  for(int i=1;i<=p;i++)
  {
   if(pre[i]%2)
   count++;
  }
  if(count==0||count==2)
  cout<<"Yes"<<endl;
  else
  cout<<"No"<<endl;
 }
  else
  cout<<"No"<<endl;
 }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值