java - 如何在给定图中快速计算n个非重叠顶点对中的一个不会在边上的概率
问题描述
我有 45 个顶点的图,我想计算如果我采用 n 个随机非重叠对,其中一个不会在边缘上的概率。当我说非重叠对时,我的意思是它们不共享任何顶点。
例如,使用 n == 2,并使用此图:
左上顶点被选中的概率是 4/5,那么如果他被选中,它与右上顶点成对的概率是 1/4。
所以结果应该是 (4/5)*(1-1/4)=0.6
我能想到的最快方法是检测哪个顶点的邻居最少,并对这个顶点进行递归。
这是我写的代码(在java中)
public class TwinNeighbor {
public static double get(byte[][] neighborsArr, int pairAmount) {
return getRec(neighborsArr, pairAmount, new boolean[neighborsArr.length]);
}
private static double getRec(byte[][] neighborsArr, int pairAmount, boolean[] deleted) {
int deleteAmount = total(deleted);
if (pairAmount == 0)
return 1;
if (pairAmount * 2 > neighborsArr.length - deleteAmount)
return 0;
int index = getIndexWithLeastNeighbors(neighborsArr, deleted);
double total = 0;
deleted[index] = true;
for (byte neighbor : neighborsArr[index]) {
if (deleted[neighbor])
continue;
deleted[neighbor] = true;
total += getRec(neighborsArr, pairAmount - 1, deleted);
deleted[neighbor] = false;
}
double probabilityIfSelected = total / (neighborsArr.length - deleteAmount - 1);
double probabilityIfNotSelected = getRec(neighborsArr, pairAmount, deleted);
deleted[index] = false;
double probabilitySelectCard = (double) pairAmount * 2 / (neighborsArr.length - deleteAmount);
return probabilitySelectCard * probabilityIfSelected + (1 - probabilitySelectCard) * probabilityIfNotSelected;
}
private static int total(boolean[] arr) {
int total = 0;
for (boolean b : arr)
if (b)
total++;
return total;
}
private static int getIndexWithLeastNeighbors(byte[][] neighborsArr, boolean[] deleted) {
int minNeighborsAmount = neighborsArr.length;
int minNeighborsIndex = -1;
for (int i = 0; i < neighborsArr.length; i++) {
if (deleted[i])
continue;
int neighborsAmount = 0;
for (byte neighbor : neighborsArr[i])
if (!deleted[neighbor])
neighborsAmount++;
if (neighborsAmount < minNeighborsAmount) {
minNeighborsAmount = neighborsAmount;
minNeighborsIndex = i;
}
}
return minNeighborsIndex;
}
}
public static void main(String[] args) {
System.out.println(1 - TwinNeighbor.get(new byte[][] {
{1},
{0,2,3,4},
{1,3,4},
{1,2,4},
{1,2,3}
}, 2));//prints 0.6000000000000001
}
有什么方法可以让我的代码运行得更快吗?
编辑:
如果 n 很小,有没有办法让它更快?(n <= 6, |V| = 45)
解决方案
不幸的是,n = |V|/2 的特殊情况相当于计算完美匹配的数量,这是一个#P-hard 问题,所以除非出现奇迹,否则你会被指数时间算法困住。
您可以通过记住每个(诱导子图,n')对的结果来获得 O(n |V| 2 |V| ) 时间算法,其中 n' ≤ n。这对 |V| 来说很昂贵 = 45 但并非不可能,特别是如果 n 很小并且您只需评估缺少 ≤ 2n 个顶点的子图。
推荐阅读
- javascript - Visual Studio Code:使用 Firefox ESR 调试 JavaScript
- markdown - pandoc 中有没有办法在代码块顶部包含文件名?
- ssl - 使用 StackExchange.Redis 与 Redis 建立 SSL 连接
- c# - 无法使用证书存储中的客户端证书,只能通过从文件加载
- android - 如何通过意图直接编辑而不是副本将 PDF 传递给 Android 上的 Adobe Reader?
- c# - RSA - 数据不能长于模数错误
- html - CKAN资源表单html“描述”字段,我如何/在哪里可以将其他字段更改为与描述相同的大小?
- gatsby - 使用 gatsby 创建新项目的命令不起作用
- azure-data-explorer - 汇总来自 customMeasurements 列的值
- dart - 将数据报数据转换为字符串 HEX