- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在编写代码,根据 Configuration Model 打乱图形的边缘.本质上,如果
我写了下面的代码来实现这个
// Instantiates an empty undirected graph.
typedef boost::adjacency_list< boost::setS,
boost::vecS,
boost::undirectedS > graph_t;
graph_t graph(9);
// Adds edges to the graph.
boost::add_edge(0, 1, graph); boost::add_edge(0, 3, graph);
boost::add_edge(0, 5, graph); boost::add_edge(0, 7, graph);
boost::add_edge(1, 2, graph); boost::add_edge(2, 3, graph);
boost::add_edge(2, 4, graph); boost::add_edge(4, 8, graph);
boost::add_edge(5, 7, graph); boost::add_edge(5, 8, graph);
boost::add_edge(6, 7, graph); boost::add_edge(7, 8, graph);
// Number of edges.
unsigned int nb_edges = boost::num_edges(graph);
// Defines a function that give a random edge.
std::random_device rd;
std::mt19937 engine(rd());
std::uniform_int_distribution<int> get_rand_edge(0, nb_edges - 1);
// Descriptors and iterators.
graph_t::vertex_descriptor v1, v2, v3, v4;
graph_t::edge_iterator e1_it, e2_it, e_end;
// Shuffles the edges, with the condition of not creating multiple edges or self-loops.
unsigned int nb_edge_swaps(0);
while(nb_edge_swaps < 10 * nb_edges)
{
// Gets the first edge.
std::tie(e1_it, e_end) = boost::edges(graph);
std::advance(e1_it, get_rand_edge(engine));
v1 = boost::source(*e1_it, graph);
v2 = boost::target(*e1_it, graph);
// Gets the second edge.
std::tie(e2_it, e_end) = boost::edges(graph);
std::advance(e2_it, get_rand_edge(engine));
v3 = boost::source(*e2_it, graph);
v4 = boost::target(*e2_it, graph);
// Avoids self-loops.
if((v1 != v3) && (v2 != v4))
{
// Avoids multiple edge.
if(boost::edge(v1, v3, graph).second == false)
{
// Avoids multiple edge.
if(boost::edge(v2, v4, graph).second == false)
{
// Destroys the old edges.
boost::remove_edge(*e1_it, graph);
boost::remove_edge(boost::edge(v3, v4, graph).first, graph);
// Creates the new edges.
boost::add_edge(v1, v3, graph);
boost::add_edge(v2, v4, graph);
// Counts the number of changes.
++nb_edge_swaps;
}
}
}
}
这似乎工作得很好,尽管速度很慢。我想知道是否有另一种聪明的方法可以更有效地完成同样的任务。我想要使用 Boost Graph Library 的解决方案,但欢迎任何想法。谢谢!
最佳答案
在没有太多指导的情况下,我创建了一些比较基准。 90 个顶点和 120 个边的计时:
完整示例详细信息 ( click for interactive charts ):
事实证明,我对邻接矩阵更快的直觉恰恰相反:
I assume it can be fixed by creating a specialized approach to selecting a random edge¹. I'll leave that as an exercise for the reader now.
使用 https://github.com/rmartinho/nonius
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/adjacency_matrix.hpp>
#include <boost/graph/edge_list.hpp>
#include <boost/graph/random.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/container/flat_set.hpp>
#include <nonius/benchmark.h++>
namespace edge_list_detail {
struct edge {
using first_type = size_t;
using second_type = size_t;
first_type s;
second_type t;
edge(first_type s, second_type t) : s(std::min(s,t)), t(std::max(s,t)) { assert(s!=t); }
bool operator<(edge const& other) const { return std::tie(s,t) < std::tie(other.s, other.t); }
};
using node_based_set = std::set<edge>;
using flat_set = boost::container::flat_set<edge>;
void reserve(node_based_set const&, size_t) {}
void reserve(flat_set& c, size_t n) { c.reserve(n); }
void erase_two(node_based_set& from, node_based_set::iterator e1, node_based_set::iterator e2) {
from.erase(e1);
from.erase(e2);
}
void erase_two(flat_set& from, flat_set::iterator e1, flat_set::iterator e2) {
if (e2<e1) std::swap(e1, e2);
from.erase(e2); // invalidates higher iterators
from.erase(e1);
}
}
typedef boost::adjacency_list < boost::setS, boost::vecS, boost::undirectedS > adj_list_t;
typedef boost::adjacency_matrix < boost::undirectedS > adj_mat_t;
static std::mt19937 engine(std::random_device{}());
static auto const sample_adj_list = [] {
using namespace boost;
adj_list_t graph(90);
generate_random_graph(graph, 90, 120, engine);
{
std::ofstream ofs("/tmp/raw.dot");
write_graphviz(ofs, graph);
}
return graph;
}();
static auto const sample_adj_mat = [] {
using namespace boost;
adj_mat_t graph(num_vertices(sample_adj_list));
for (auto e : make_iterator_range(edges(sample_adj_list))) {
add_edge(source(e, sample_adj_list), target(e, sample_adj_list), graph);
}
return graph;
}();
template <typename graph_t> auto nth_edge(graph_t& graph, size_t n) {
return std::next(boost::edges(graph).first, n);
}
auto nth_edge(edge_list_detail::node_based_set& lst, size_t n) {
return std::next(lst.begin(), n);
}
auto nth_edge(edge_list_detail::flat_set& lst, size_t n) {
return std::next(lst.begin(), n);
}
template <typename graph_t> void OP_algo(nonius::chronometer& cm, graph_t graph) {
// Number of edges.
cm.measure([&] {
unsigned int nb_edges = boost::num_edges(graph);
// Defines a function that give a random edge.
std::uniform_int_distribution<int> get_rand_edge(0, nb_edges - 1);
// Descriptors and iterators.
typename graph_t::vertex_descriptor v1, v2, v3, v4;
typename graph_t::edge_iterator e1_it, e2_it, e_end;
// Shuffles the edges, with the condition of not creating multiple edges or self-loops.
unsigned int nb_edge_swaps(0);
while(nb_edge_swaps < 10 * nb_edges)
{
{
e1_it = nth_edge(graph, get_rand_edge(engine));
v1 = boost::source(*e1_it, graph);
v2 = boost::target(*e1_it, graph);
e2_it = nth_edge(graph, get_rand_edge(engine));
v3 = boost::source(*e2_it, graph);
v4 = boost::target(*e2_it, graph);
}
// Avoids self-loops.
if((v1 != v3) && (v2 != v4))
{
// Avoids multiple edge.
if(boost::edge(v1, v3, graph).second == false)
{
// Avoids multiple edge.
if(boost::edge(v2, v4, graph).second == false)
{
// Destroys the old edges.
boost::remove_edge(*e1_it, graph);
boost::remove_edge(boost::edge(v3, v4, graph).first, graph);
// Creates the new edges.
boost::add_edge(v1, v3, graph);
boost::add_edge(v2, v4, graph);
// Counts the number of changes.
++nb_edge_swaps;
}
}
}
}
return;
{
std::ofstream ofs("/tmp/shuffled.dot");
boost::write_graphviz(ofs, graph);
}
});
}
template <typename list_t> void edge_list_algo(nonius::chronometer& cm, list_t& lst) {
cm.measure([&] {
unsigned int nb_edges = lst.size();
// Defines a function that give a random edge.
std::uniform_int_distribution<int> get_rand_edge(0, nb_edges - 1);
// Shuffles the edges, with the condition of not creating multiple edges or self-loops.
unsigned int nb_edge_swaps(0);
while(nb_edge_swaps < 10 * nb_edges)
{
auto e1 = nth_edge(lst, get_rand_edge(engine));
auto v1 = e1->s;
auto v2 = e1->t;
auto e2 = nth_edge(lst, get_rand_edge(engine));
auto v3 = e2->s;
auto v4 = e2->t;
// Avoids self-loops.
// Avoids multiple edge.
if ((v1 == v3) || (v2 == v4) || lst.count({v1,v3}) || lst.count({v2,v4}))
continue;
// swap edges
edge_list_detail::erase_two(lst, e1, e2);
lst.emplace(v1, v3);
lst.emplace(v2, v4);
// Counts the number of changes.
++nb_edge_swaps;
}
return;
});
}
template <typename edge_list>
void edge_list_config(nonius::chronometer& cm) {
using namespace boost;
edge_list lst;
{
edge_list_detail::reserve(lst, num_edges(sample_adj_list));
for (auto e : make_iterator_range(edges(sample_adj_list))) {
lst.emplace(source(e, sample_adj_list), target(e, sample_adj_list));
}
}
edge_list_algo(cm, lst);
typedef boost::edge_list<typename edge_list::iterator> graph_t;
graph_t graph(lst.begin(), lst.end());
{
std::ofstream ofs("/tmp/edge_list.dot");
//boost::write_graphviz(ofs, graph);
}
}
NONIUS_BENCHMARK("original_adj_list", [](nonius::chronometer cm) { OP_algo(cm, sample_adj_list); });
NONIUS_BENCHMARK("original_adj_matrix", [](nonius::chronometer cm) { OP_algo(cm, sample_adj_mat); });
NONIUS_BENCHMARK("node_based_edge_list",[](nonius::chronometer cm) { edge_list_config<edge_list_detail::node_based_set>(cm); });
NONIUS_BENCHMARK("flat_edge_list", [](nonius::chronometer cm) { edge_list_config<edge_list_detail::flat_set>(cm); });
#define NONIUS_RUNNER
#include <nonius/main.h++>
创建图表:
./test -r html -o stats.html
¹(下面的nth_edge
是通用,对于 adjacency_matrix 效率不高)。
关于c++ - 如何有效地洗牌图中的边,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40610242/
这是一个面试问题。请给一些提示: 使用 vector 实现一个方法,洗一副牌。 public class Card { private int value; Card(int v) {
我非常是 C++ 的新手,我还没有完全理解基本概念,但我的教授希望我们编写一个算法来洗牌和展示一副纸牌和一副牌需要表示为二维数组。 但是我在模拟一副纸牌时遇到了麻烦! #include #inclu
我想用 php 创建随机桥牌的集合。我认为我可以将一副有序的纸牌编码为下面的字符串 $deal(考虑到大写和小写时,我喜欢它有 52 个字母)。我发现了 php 函数 str_shuffle。所以我想
我想随机重新排序矩阵 A 的行以生成另一个新矩阵。如何在 R 中做到这一点? 最佳答案 使用 sample()以(伪)随机顺序生成行索引并使用 [ 重新排列矩阵. ## create a matrix
我计划在 android-Java 上开发一个简单的纸牌游戏,在我的应用程序中,我洗牌,所以我想知道将我的牌组存储在数组或堆栈中的最佳方法是什么..?堆栈的唯一问题是我不知道如何对其进行洗牌。 最佳答
我正在尝试创建一种方法,使用 Arraylist 随机打乱基元数组。我想知道 .get(); 方法是否是在我的 Arraylist 上使用的正确方法,在 for 循环中的普通数组上它只是 array[
我是 C++ 的新手,但是,我正在尝试创建一些盐和胡椒噪音。它几乎完成了,只是在这之间我想洗牌一个整数数组,无论我做什么,无论我使用什么洗牌功能,我总是得到令人讨厌的“从这里需要”,它没有告诉我任何事
我被要求编写一个程序(主要是一个方法)来洗牌。我编写了以下程序: public class Deck { //////////////////////////////////////// // Dat
我已经看到其他与此相关的话题,但似乎没有一个能回答我的问题。我尝试在 vector 上使用 shuffle() 函数,但我一直收到错误消息: deck_of_cards.cpp:34:5: error
是否与sort 一致导致更随机的数组或者是 sort这里只是浪费? use List::Util qw(shuffle); @random1 = shuffle sort keys %vocables
首先,这个问题是从 this 中摘下来的问题。我这样做是因为我认为这部分比较长问题的子部分更大。如有冒犯,请见谅。 假设您有一个生成随机性的算法。现在你如何测试它?或者更直接地说 - 假设您有一个洗牌
我正在制作一个配对游戏,其中有 8 个 ImageView 和 4 个不同的图像。我想知道页面何时加载是否可以交换 ImageView 的位置? 让每张图片的顺序每次都变? 最佳答案 试试这个:
我正在制作一款纸牌游戏,需要在游戏开始前洗牌。通过在将数组插入数据库之前对其进行混洗,可以毫无问题地完成此操作。然而,在游戏开始后,有些情况下玩家需要洗牌。我想到的唯一方法是重新洗牌后重新插入套牌,但
我正在运行一个网站,其中用户导航子目录的唯一方式是通过随机页面(类似于维基百科的随机页面功能)。我已经实现了调用随机页面的代码并且它工作正常,但我想尽量减少在 onclick 执行后再次调用同一页面的
我想用一个条件打乱一个 2d Numpy 数组。例如,仅随机播放非零值。 import numpy as np a = np.arange(9).reshape((3,3)) a[2,2] = 0 #
我将如何获取 RLMArray 并对其进行洗牌,以便 RLMArray 中的当前项目是随机的。 我已经查看了 RLMArray 的文档,但是我没有看到对其进行洗牌的好方法。 最佳答案 你最好的选择可能
在我的 Qt c++ 应用程序中,我有一个包含一组 QString 值的 QStringList!我想随机播放(任意更改 QStringList 中 QString 的位置)。 perl中是否有任何默
我知道它是如何工作的,但我在排序和配对方面仍然有问题,这样我才能确定获胜者。 将它们配对(配对是具有相同值(value)的卡片。)例如,红心 A 和黑桃 A 组成一对。然后我数那些对。拥有最高对子的手
我有一组这样的 div: 我需要在点击其中一个红色 div 时随机播放它们,但点击的 div 应该始终与黄色 div 交换。 fiddle here $('.box-red').click(funct
// deck of cards // below are initializations #include #include #include using namespace std; int
我是一名优秀的程序员,十分优秀!