98 lines
2.4 KiB
C++
98 lines
2.4 KiB
C++
#include "testlib.h"
|
|
|
|
#include <iomanip>
|
|
#include <thread>
|
|
#include <tuple>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
using namespace std;
|
|
|
|
using ll = unsigned long long;
|
|
using pll = pair<ll, ll>;
|
|
|
|
const double eps = 1e-3;
|
|
|
|
void generate_edges_parallel(ll s_start, ll s_end, ll n, const vector<ll> &cnt,
|
|
unsigned int thread_seed,
|
|
vector<tuple<ll, ll, double>> &buffer) {
|
|
random_t thread_rnd;
|
|
thread_rnd.setSeed(thread_seed);
|
|
|
|
unordered_map<ll, ll> selected;
|
|
|
|
for (ll s = s_start; s < s_end; ++s) {
|
|
ll k = cnt[s];
|
|
if (k == 0) continue;
|
|
|
|
selected.clear();
|
|
|
|
for (ll i = 0; i < k; ++i) {
|
|
ll range_size = (n - 1) - i;
|
|
ll j = thread_rnd.next(1uLL, range_size);
|
|
|
|
ll val_j = selected.count(j) ? selected[j] : j;
|
|
ll val_last =
|
|
selected.count(range_size) ? selected[range_size] : range_size;
|
|
|
|
ll e = (val_j < s) ? val_j : val_j + 1;
|
|
double len = thread_rnd.next(eps, 1.0 / eps);
|
|
|
|
buffer.emplace_back(s, e, len);
|
|
|
|
selected[j] = val_last;
|
|
}
|
|
}
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
// 메인 RNG 초기화
|
|
registerGen(argc, argv, 1);
|
|
|
|
ll n = opt<ll>("N");
|
|
ll m = opt<ll>("M");
|
|
|
|
println(n, m);
|
|
|
|
vector<ll> cnt(n + 1, 0);
|
|
for (ll i = 0; i < m; ++i) {
|
|
ll s = rnd.next(1uLL, n);
|
|
cnt[s]++;
|
|
}
|
|
|
|
const int num_threads = thread::hardware_concurrency();
|
|
vector<thread> threads;
|
|
|
|
vector<unsigned int> thread_seeds;
|
|
vector<vector<tuple<ll, ll, double>>> thread_buffers(num_threads);
|
|
|
|
for (int i = 0; i < num_threads; ++i) {
|
|
thread_seeds.push_back(rnd.next(1u, 1000000u));
|
|
}
|
|
|
|
ll s_batch_size = (n + num_threads) / num_threads;
|
|
ll s_current = 1;
|
|
|
|
for (int i = 0; i < num_threads; ++i) {
|
|
ll s_start = s_current;
|
|
ll s_end = min(s_start + s_batch_size, n + 1);
|
|
if (s_start >= s_end) break;
|
|
|
|
threads.emplace_back(generate_edges_parallel, s_start, s_end, n,
|
|
ref(cnt), thread_seeds[i], ref(thread_buffers[i]));
|
|
|
|
s_current = s_end;
|
|
}
|
|
|
|
for (auto &t : threads) {
|
|
t.join();
|
|
}
|
|
|
|
cout << fixed << setprecision(15);
|
|
for (int i = 0; i < num_threads; ++i) {
|
|
for (const auto &edge : thread_buffers[i]) {
|
|
println(get<0>(edge), get<1>(edge), get<2>(edge));
|
|
}
|
|
}
|
|
}
|