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

相关文章

如何测试计算机的内存是否存在问题? 判断电脑内存故障的多种方法

《如何测试计算机的内存是否存在问题?判断电脑内存故障的多种方法》内存是电脑中非常重要的组件之一,如果内存出现故障,可能会导致电脑出现各种问题,如蓝屏、死机、程序崩溃等,如何判断内存是否出现故障呢?下... 如果你的电脑是崩溃、冻结还是不稳定,那么它的内存可能有问题。要进行检查,你可以使用Windows 11

使用Python实现生命之轮Wheel of life效果

《使用Python实现生命之轮Wheeloflife效果》生命之轮Wheeloflife这一概念最初由SuccessMotivation®Institute,Inc.的创始人PaulJ.Meyer... 最近看一个生命之轮的视频,让我们珍惜时间,因为一生是有限的。使用python创建生命倒计时图表,珍惜时间

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

hdu2289(简单二分)

虽说是简单二分,但是我还是wa死了  题意:已知圆台的体积,求高度 首先要知道圆台体积怎么求:设上下底的半径分别为r1,r2,高为h,V = PI*(r1*r1+r1*r2+r2*r2)*h/3 然后以h进行二分 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#includ

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2093 考试排名(sscanf)

模拟题。 直接从教程里拉解析。 因为表格里的数据格式不统一。有时候有"()",有时候又没有。而它也不会给我们提示。 这种情况下,就只能它它们统一看作字符串来处理了。现在就请出我们的主角sscanf()! sscanf 语法: #include int sscanf( const char *buffer, const char *format, ... ); 函数sscanf()和

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :