Codeforces 405 E. Graph Cutting ( DFS )

 

题意:

给n个点,m条边,将这个图拆成多个子图,每个子图里面有两条相邻的边(也就是每个子图 3个点2条边),当然每条边只能属于一个子图,如果不能拆分成功,则No solution, 否则,将每个子图的3个顶点(x,y,z)输出 (这个子图包含 x到y 的边 , y到z的边 )

思路:
m是奇数,则不能拆分。
m是偶数,可以拆分。

1、将图形看成以1为树根的一棵“树”,这棵树会有环,把它当成一颗简单树来分析思路,如下图的一棵树。
  题目中的是无向图,画图的时候不小心画成了有向的了,,,,,(只要把它当成无向就好了,忽视箭头就好了)



2、从树根 1 开始遍历,一直到叶子节点(或者遇到已经被访问过的点),然后进行一些操作,然后回溯。
操作为:
给每个点一个队列来存放它的可用的子节点(存进去的可用的子节点,指的是这个点到子节点的边还未用过)。
然后让这些可用的子节点两两一对,(即child1,root,child2 为一个子图 )。
  如果可用的子节点为奇数,则说明有一条到子节点的边没有被用过,则另外需要当前这个点到它父亲节点的一条边,使之构成一个子图。
例如 图中的 节点3 : 它有3个子节点,(6—3—8)一个子图,3—9这条边则需要和3—1这条边组成一个子图(1—3—9),所以节点3这个点不再是节点1的可用的子节点了,因为1—3 这条边已经被用过了。
  如果可用的子节点是偶数,则不需要直接构成子图就好了。当然这个节点仍然是它父亲节点的可用子节点。如节点2仍然是节点1的子节点。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 #include<queue>
 7 
 8 using namespace std;
 9 
10 const int T=1e5+5;
11 
12 struct node
13 {
14     int x,num;
15 }t;
16 
17 vector < node > Q[T];
18 bool flag[T];
19 
20 int dfs( int now )
21 {
22     int l=(int)Q[now].size(),r,v1,v2;
23     node k;
24     queue < int > q;   // 注意==>是每个节点都有一个队列
25     for(int i=0;i<l;i++)
26     {
27         k=Q[now][i];
28         if( flag[k.num] ) continue;
29         flag[k.num]=1;
30         r = dfs( k.x );
31         if( r ) printf("%d %d %d\n",now,k.x,r); // 说明 now 节点的子节点有一条未用的边
32         else q.push( k.x );  //否则将这个节点存入到队列里
33     }
34     while( q.size() >= 2 )
35     {
36         v1=q.front();
37         q.pop();
38         v2=q.front();
39         q.pop();
40         printf("%d %d %d\n",v1,now,v2);
41     }
42     if( !q.empty() )
43     {
44         v1=q.front();
45         return v1;  // 如果队列里面有剩余,则将此队列里的点返回回去和其父节点,父节点的父节点构成一个子图
46     }
47     return 0;
48 }
49 
50 int main( )
51 {
52     int n,m,a,b;
53     while(~scanf("%d%d",&n,&m))
54     {
55         for(int i=0;i<=n;i++)
56             Q[i].clear();
57         for(int i=1;i<=m;i++)
58         {
59             scanf("%d%d",&a,&b);
60             t.num=i;
61             t.x=b;
62             Q[a].push_back( t );
63             t.x=a;
64             Q[b].push_back( t );
65         }
66         if( m%2 ) printf("No solution\n");
67         else{
68 
69             memset(flag,0,sizeof(flag));
70             dfs( 1);
71         }
72     }
73     return 0;
74 }
View Code

 



转载于:https://www.cnblogs.com/lysr--tlp/p/adfs.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值