计算二分图(bipartite graph)交叉点(crossing)的数量

2023-11-28 01:30

本文主要是介绍计算二分图(bipartite graph)交叉点(crossing)的数量,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

对于一个二分图,如果图的两个部分的顶点都按照顺序分别排列在一对平行线上,如下图,如何计算这个二分图的边有多少个交叉点呢?需要注意两点:1. 在图的顶点处连接的边不认为产生了交叉点,如下图在c、d、B和D点连接的边;2. 如果交叉点有两条以上边经过,这些边中的每对边都要算作产生了一个交叉点,如下图Bd、Cc和Db算作产生了3个交叉点。
在这里插入图片描述
那么这个图共有多少个交叉点呢?数一数就可以得出结论,答案是5个。

如果不手工数的话,该怎样计算呢?就以上图为例,首先对图的下半部分顶点按照左右顺序编号为0,1,2,3,然后对上半部分图顶点也进行编号,编号为连接的下半部分顶点的编号,如果连接了多个下半部分的顶点,也要从小到大编上多个编号。则上图上半部分顶点编号为2,0,3,2,1,3。可以看出来,上半部分顶点编号每对逆序(左侧的数大于右侧的数)编号都说明产生了一个交叉点。上图共有5对逆序编号(2,0),(2,1),(3,2),(3,1),(2,1),因此共有5个交叉点。现在问题就转化成了如何计算一个数组逆序对的数量,暴力的O(n*n)算法自然很容易想到,但是有没有更高效的方法呢?自然是有的,参考Counting inversion基于归并排序的算法可在O(n*log(n))时间复杂度内实现计算交叉点数量的目的。
原理其实很简单,在归并两个数组有一个比较两个数组元素值的过程,在比较时可以维护一个记录逆序对的变量。如下图:
在这里插入图片描述
将A和B归并至C时,发现0小于1,因此将0放入C中,然后发现当前B中的1要小于A中的2,这说明产生了逆序对,逆序对有几个呢?B中的1不止小于A中的2,还小于A中的3,准确的说是A中未被归并的部分和1都组成了一个逆序对。将上述过程进行迭代和递归就可以计算出逆序对的数量,也就是二分图交叉点的数量。
代码如下:

#include <stdio.h>
#include <set>
#include <map>
#include <vector>
#include <algorithm>int mergeAndCount(std::vector<int> &data, int begin, int mid, int end)
{std::vector<int> merged;int result = 0;int i = begin;int j = mid;while (i < mid && j < end){merged.push_back(std::min(data[i], data[j]));if (data[i] > data[j]){result += (mid - i);j++;}else{i++;}}if (i == mid){merged.insert(merged.end(), data.begin() + j, data.begin() + end);}else // j == end{merged.insert(merged.end(), data.begin() + i, data.begin() + mid);}for (int k = 0; k < end - begin; k++){data[k + begin] = merged[k];}return result;
}int sortAndCount(std::vector<int> &data, int begin, int end)
{if ((end - begin) <= 1){return 0;}int mid = (begin + end) / 2;int leftCount = sortAndCount(data, begin, mid);int rightCount = sortAndCount(data, mid, end);int mergeCount = mergeAndCount(data, begin, mid, end);return leftCount + rightCount + mergeCount;
}int twoLayerCrossing(std::vector<std::string> &top, std::vector<std::string> &bottom, std::map<std::string, std::set<std::string> > &adj)
{std::vector<int> toSortAndCount;std::map<std::string, int> bottomName2Order;for (int i = 0; i < bottom.size(); i++){bottomName2Order[bottom[i]] = i;}for (auto &topName : top){std::vector<int> tmp;for (auto &name : adj[topName]){if (bottomName2Order.find(name) != bottomName2Order.end()){tmp.push_back(bottomName2Order.at(name));}}std::sort(tmp.begin(), tmp.end());toSortAndCount.insert(toSortAndCount.end(), tmp.begin(), tmp.end());}printf("Array: ");for (auto num : toSortAndCount){printf("%d ", num);}printf("\n");return sortAndCount(toSortAndCount, 0, toSortAndCount.size());
}int main()
{std::vector<std::string> top = {"A", "B", "C", "D"};std::vector<std::string> bottom = {"a", "b", "c", "d"};std::map<std::string, std::set<std::string>> adj;adj["A"] = {"c"};adj["B"] = {"a", "d"};adj["C"] = {"c"};adj["D"] = {"b", "d"};int result = twoLayerCrossing(top, bottom, adj);printf("result: %d\n", result);
}

这篇关于计算二分图(bipartite graph)交叉点(crossing)的数量的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

使用C#代码计算数学表达式实例

《使用C#代码计算数学表达式实例》这段文字主要讲述了如何使用C#语言来计算数学表达式,该程序通过使用Dictionary保存变量,定义了运算符优先级,并实现了EvaluateExpression方法来... 目录C#代码计算数学表达式该方法很长,因此我将分段描述下面的代码片段显示了下一步以下代码显示该方法如

如何用Java结合经纬度位置计算目标点的日出日落时间详解

《如何用Java结合经纬度位置计算目标点的日出日落时间详解》这篇文章主详细讲解了如何基于目标点的经纬度计算日出日落时间,提供了在线API和Java库两种计算方法,并通过实际案例展示了其应用,需要的朋友... 目录前言一、应用示例1、天安门升旗时间2、湖南省日出日落信息二、Java日出日落计算1、在线API2

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

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

poj 1113 凸包+简单几何计算

题意: 给N个平面上的点,现在要在离点外L米处建城墙,使得城墙把所有点都包含进去且城墙的长度最短。 解析: 韬哥出的某次训练赛上A出的第一道计算几何,算是大水题吧。 用convexhull算法把凸包求出来,然后加加减减就A了。 计算见下图: 好久没玩画图了啊好开心。 代码: #include <iostream>#include <cstdio>#inclu

uva 1342 欧拉定理(计算几何模板)

题意: 给几个点,把这几个点用直线连起来,求这些直线把平面分成了几个。 解析: 欧拉定理: 顶点数 + 面数 - 边数= 2。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc

uva 11178 计算集合模板题

题意: 求三角形行三个角三等分点射线交出的内三角形坐标。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <

XTU 1237 计算几何

题面: Magic Triangle Problem Description: Huangriq is a respectful acmer in ACM team of XTU because he brought the best place in regional contest in history of XTU. Huangriq works in a big compa

poj 2976 分数规划二分贪心(部分对总体的贡献度) poj 3111

poj 2976: 题意: 在n场考试中,每场考试共有b题,答对的题目有a题。 允许去掉k场考试,求能达到的最高正确率是多少。 解析: 假设已知准确率为x,则每场考试对于准确率的贡献值为: a - b * x,将贡献值大的排序排在前面舍弃掉后k个。 然后二分x就行了。 代码: #include <iostream>#include <cstdio>#incl