Hdu 1892Poj 2492 A Bug's Life[判断二分图 || 种类并查集]

2024-06-07 03:58

本文主要是介绍Hdu 1892Poj 2492 A Bug's Life[判断二分图 || 种类并查集],希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

昨天一天就弄着一道题了。

一开始的时候想法是判断是否存在奇数圈。如果存在,肯定有同性恋存在。

后来看到了别人的想法。就是,判二分图。

后来在,上课翻离散书的时候看到一个定理:n阶无向图是一个二分图当且仅当图中没有无奇数圈。

这样,判奇数圈和判二分图就是一个意思了。

那么,怎么来判奇数圈或者二分图呢???

搜索了一下,看到一种染色法判断二分图。意思就是,将图中的节点染色,如果能够把所有的点染成不同的两个颜色,并且不产生矛盾(相连的节点颜色相同);

如图所示:


可以用BFS或DFS实现:

BFS:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#define CLR(arr,val) memset(arr,val,sizeof(arr))
using namespace std;const int N=2005;
int color[N],n,m;
bool vis[N];
vector<int> map[N];bool bfs(int s){queue<int> q;q.push(s);color[s]=1;while(!q.empty()){int now=q.front();q.pop();for(int i=1;i<=10000000;i++);printf("now %d\n",now);if(!vis[now]){int len=map[now].size();for(int i=0;i<len;i++){int des=map[now][i];q.push(des);if(color[des]==-1)color[des]=color[now]==0?1:0;else {if(color[des]==color[now]) return false;else continue;}}vis[now]=true;}}return true;
}int main(){freopen("1.txt","r",stdin);int T,k=1;scanf("%d",&T);while(T--){CLR(color,-1);CLR(vis,0);CLR(map,0);scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int a,b;scanf("%d%d",&a,&b);map[a].push_back(b);map[b].push_back(a);}int i;printf("Scenario #%d:\n",k++);for(i=1;i<=n;i++){if(!vis[i]){bool flag=bfs(i);if(!flag){printf("Suspicious bugs found!\n\n");break;}}}if(i>n) printf("No suspicious bugs found!\n\n");}return 0;
}

DFS:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#define CLR(arr,val) memset(arr,val,sizeof(arr))
using namespace std;const int N=2003;
int n,m,color[N];
vector<int> map[N];
bool vis[N];bool dfs(int s){vis[s]=true;int len=map[s].size();for(int i=0;i<len;i++){int des=map[s][i];if(color[des]==color[s]) return false;if(color[des]==-1){color[des]=color[s]==0?1:0;if(!dfs(des)) return false;}}return true;
}
int main(){freopen("1.txt","r",stdin);int T,k=1;scanf("%d",&T);while(T--){CLR(map,0);CLR(vis,0);CLR(color,-1);scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int a,b;scanf("%d%d",&a,&b);map[a].push_back(b);map[b].push_back(a);}printf("Scenario #%d:\n",k++);bool flag=false;for(int i=1;i<=n;i++){if(!vis[i]){color[i]=1;if(!dfs(i)){flag=true;break;}}}if(flag) printf("Suspicious bugs found!\n\n");else printf("No suspicious bugs found!\n\n");}return 0;
}

无论BFS还是DFS,需要注意的是,所有的节点可能出现在不同的集合中。需要多次BFS或DFS。


这个问题大多数还是用并查集做的。。表示很有压力。。

可以说是并查集的一种应用。。。大多数网上说是种类并查集。。。也就是说分类了。。网上找了一种说法。很是简单易于理解。。

下面一种方法是种类并查集。终于明白原理是为什么了。种类并查集是给每个结点一个权值。然后在合并和查找的时候根据情况对权值来进行维护。对于这个题来说,就可以给每个节点设置一个0或1的权值。0代表与根节点同性,1代表与根节点异性。与根节点的关系可以在查找的时候利用递归从根节点向叶子不断进行维护。利用抵消的原理,不断相加余2就行了。然后合并的时候,由于根节点的性别是不确定的,不能简单简单的合并就完了,还要考虑两颗树的根节点之间的关系。这时候,要想使两个异性结点一个为0一个为1,
只要将被合并的那棵树的根节点维护一下就可以,下面的所有的结点的值都可以在查找的时候由这个根节点来决定。因为,如果根节点为0,那么下面的都不会改变,如
果为1的话,那下面的都会改变。剩下的就是考虑这个根节点要怎么确定。的时候由这个根节点来决定。因为,如果根节点为0,那么下面的都不会改变,如果为1的话,那下面的都会改变。剩下的就是考虑这个根节点要怎么确定。要想使输入两个异性结点一个为0一个为1,假如此时在两颗树中显示的是同性,那么只要把根节点设置成1,否则,就设置成0.这地方应该很好想,就不解释了。这时
可以用两者权值之和加1余2来实现。

上面的解释很是给力。。从上面可以看出好的解释,都是思路明了,句句有用。。。表示自己还没有达到这种情况。。     努力去达到这种程度吧。。

加一图更易于了解。。


Code:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>
using namespace std;const int N = 1e3 * 2 + 5;
int father[N], sex[N];
int n, m;void Init()
{for(int i = 1; i <= n; i ++){father[i] = i;sex[i] = 0;}
}int find(int x)
{if(x != father[x]){int tmp = father[x];father[x] = find(father[x]);sex[x] = (sex[x] + sex[tmp]) % 2;}return father[x];// must return father[x]..
}bool Union(int x, int y)
{int a = find(x);int b = find(y);if(a == b && sex[x] == sex[y]) return true;else {father[a] = b;sex[a] = (sex[x] + sex[y] + 1) % 2;}return false;
}int main()
{int T, k = 0;scanf("%d", &T);while(T --){scanf("%d %d", &n, &m);Init();int x, y;bool flag = false;for(int i = 1;  i <= m; i ++){scanf("%d %d", &x, &y);if(flag) continue;if(Union(x, y)) flag = true;}printf("Scenario #%d:\n", ++ k);if(flag) puts("Suspicious bugs found!\n");else puts("No suspicious bugs found!\n");}return 0;
}

种类并查集。get。。


这篇关于Hdu 1892Poj 2492 A Bug's Life[判断二分图 || 种类并查集]的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1038111

相关文章

随想录 Day 69 并查集 107. 寻找存在的路径

随想录 Day 69 并查集 107. 寻找存在的路径 理论基础 int n = 1005; // n根据题目中节点数量而定,一般比节点数量大一点就好vector<int> father = vector<int> (n, 0); // C++里的一种数组结构// 并查集初始化void init() {for (int i = 0; i < n; ++i) {father[i] = i;}

Java面试八股之怎么通过Java程序判断JVM是32位还是64位

怎么通过Java程序判断JVM是32位还是64位 可以通过Java程序内部检查系统属性来判断当前运行的JVM是32位还是64位。以下是一个简单的方法: public class JvmBitCheck {public static void main(String[] args) {String arch = System.getProperty("os.arch");String dataM

气象站的种类和应用范围可以根据不同的分类标准进行详细的划分和描述

气象站的种类和应用范围可以根据不同的分类标准进行详细的划分和描述。以下是从不同角度对气象站的种类和应用范围的介绍: 一、气象站的种类 根据用途和安装环境分类: 农业气象站:专为农业生产服务,监测土壤温度、湿度等参数,为农业生产提供科学依据。交通气象站:用于公路、铁路、机场等交通场所的气象监测,提供实时气象数据以支持交通运营和调度。林业气象站:监测林区风速、湿度、温度等气象要素,为林区保护和

【Python如何输入升高和体重判断你是偏胖还是偏瘦】

1、求体质指数得Python代码如下: # BMI(Body Mass Index)指数:简称体质指数,# 是国际上常用的衡量人体胖瘦程度以及是否健康的一个标准。# 常用指标:BMI<18.5 偏瘦 18.5<=MBI<=24 正常 MBI>24 偏胖# 计算公式:BMI=体重kg/身高的平方ma = eval(input("请输入你的体重(kg):")) # 输入体重b = e

算法11—判断一个树是不是二叉查询树

问题: 给定一个二叉树,判断它是否是二叉查询树。 思路: 要判断是否是二叉查询树,标准就是看每一个节点是否满足:1、左节点及以下节点的值比它小;2、右节点及以下节点的值比它大。当然,前提是子节点都存在的情况。所以,我们需要从根节点不断向下递归,只要所有节点都满足,那么就是BST,否则,就不是。 代码: [java]  view plain copy pri

算法7— 判断一个单链表是否有环,如果有,找出环的起始位置

第一种方法是从单链表head开始,每遍历一个,就把那个node放在hashset里,走到下一个的时候,把该node放在hashset里查找,如果有相同的,就表示有环,如果走到单链表最后一个node,在hashset里都没有重复的node,就表示没有环。 这种方法需要O(n)的空间和时间。 第二种方法是设置两个指针指向单链表的head, 然后开始遍历,第一个指针走一步,第二个指针走两步,如果没

算法6— 判断两个链表是否相交

问题: 给出两个单向链表的头指针,比如h1、h2,判断链表是否相交,如果不相交返回NULL;如果相交,返回指向第一个相交节点的指针。时间复杂度控制在O(n)。 分析: 如果两单向链表相交的话,一定是Y型相交,不可能出现X型,弄清楚这点后接下来的工作就是: (1)先找到h1,h2的最后一个节点L1和L2,同时记录节点数量a,b;(这里假设 a > b) (2)判断最后一个节点是否相同

上海邀请赛 A题目 HDU 5236(dp)

先求出没有ctrl+s的时候构造长度为i的期望f[i] 。然后枚举保存的次数,求出最小即可。 #include<cstdio>#include<cstdio>#include<cmath>#include<queue>#include<stack>#include<string>#include<cstring>#include<iostream>#include<map>

poj 3294(Life Forms) 2分+ 后缀数组

我曾用字符串hash写,但是超时了。只能用后最数组了。大致思路:用不同的符号吧字符串连接起来,构建后缀数组,然后2分答案,依次扫描后缀数组,看是否瞒住条件。 VIEW CODE #include<cstdio>#include<vector>#include<cmath>#include<algorithm>#include<cstring>#include<cassert>#

hdu 2586 树上点对最近距离 (lca)

,只要知道dis[i][j]=dis[i][root]+dis[j][root]-2*dis[Lca(i,j)][root].   其中root为树的根节点,LCA(i,j)为i,j的最近公共祖先。 所以我们先把所有的询问储存下来,然后离线直接查询。复杂度是o(n+q)的。 VIE #include<cstdio>#include<algorithm>#include<i