【模板】随机数据生成器

最近打了一次 Codeforces ,发现有很多小 bug 其实可以用随机数据 + assert 就能找出来的。而且也能验证一些猜想或者打表。每次都写这个东西太耗时间了。现在临时写一个后面慢慢完善。

namespace RandomGenerator {

const int MAXN = 500;
const int MAXM = 200000;
const int MAXAI = 100;

const int rnd_seed = chrono::system_clock::now().time_since_epoch().count();
//const int rnd_seed = 19937;
mt19937_64 rnd (rnd_seed);  // 调用rnd()生成uint_64_t类型

ll randInt (ll x) {
    // [1, x]
    return rnd() % x + 1;
}

ll randInt (ll l, ll r) {
    // [l, r],可以有负数
    return rnd() % (r - l + 1) + l;
}

void genArray (int &n, int *a) {
    n = randInt (MAXN);
    for (int i = 1; i <= n; ++i) {
        a[i] = randInt (MAXAI);
    }
}

void genTree (int &n, int *p) {
    // 生成一棵树,p[i]表示i节点的父亲是谁,且p[i]<i
    // 根一定是1
    n = randInt (MAXN);
    p[1] = 0;
    for (int i = 2; i <= n; ++i) {
        p[i] = randInt (1, i - 1);
    }
}

void genTree (int &n, int *x, int *y) {
    n = randInt (MAXN);
    pii g[MAXN];
    g[1] = {0, 0};
    for (int i = 2; i <= n; ++i) {
        g[i] = {i, randInt (1, i - 1) };
    }
    random_shuffle (g + 1 + 1, g + 1 + n);
    for (int i = 1; i <= n - 1; ++i) {
        if (rnd() % 2 == 1) {
            swap (g[i + 1].first, g[i + 1].second);
        }
        x[i] = g[i + 1].first;
        y[i] = g[i + 1].second;
    }
//    WTN (x, n - 1);
//    WTN (y, n - 1);
}

void genGraph (int &n, int &m, int *x, int *y) {
    genTree (n, x, y);
    m = randInt (n - 1, min (1LL * MAXM, 1LL * n * (n - 1) / 2));

    set<pii> S;
    for (int i = 1; i <= n - 1; ++i) {
        pii pi = {x[i], y[i]};
        if (pi.first > pi.second) {
            swap (pi.first, pi.second);
        }
        S.insert (pi);
    }

    for (int i = n; i <= m; ++i) {
        x[i] = randInt (n);
        y[i] = randInt (n);
        if (x[i] == y[i]) {
            --i;
            continue;
        }
        if (x[i] > y[i]) {
            swap (x[i], y[i]);
        }
        if (S.count ({x[i], y[i]})) {
            --i;
            continue;
        }
        S.insert ({x[i], y[i]});
    }

    assert (S.size() == m);

    vector<pii> V (S.begin(), S.end());
    random_shuffle (V.begin(), V.end());

    for (int i = 1; i <= m; ++i) {
        x[i] = V[i - 1].first;
        y[i] = V[i - 1].second;
        if (rnd() % 2 == 1) {
            swap (x[i], y[i]);
        }
    }

}
};

using namespace RandomGenerator;

int n;
int x[200005];
int y[200005];

vector<int> G[200005];
bool vis[200005];

int cnt = 0;
void dfs (int u) {
    ++cnt;
    vis[u] = 1;
//    printf ("u=%d\n", u);
    for (int v : G[u]) {
        if (vis[v] == 1) {
//            printf ("  v=%d u=%d\n", v, u);
            continue;
        };
//        printf ("  v=%d u=%d\n", v, u);
        dfs (v);
    }
}

void solve() {
    int m;
    genTree (n, x, y);
    WT (n);
//    WTN (x, m);
//    WTN (y, m);
    for (int i = 1; i <= n; ++i) {
        G[i].clear();
        vis[i] = 0;
    }
    for (int i = 1; i <= n - 1; ++i) {
        G[x[i]].push_back (y[i]);
        G[y[i]].push_back (x[i]);
    }
    cnt = 0;
    dfs (1);
    assert (cnt == n);
    puts ("?");
}

目前好像只能生成随机的联通图,且(无重边无自环),通过正确限制m的上限才能跑出结果。可能后面可以生成一些不平衡的树或者不平衡的图(菊花图)看一下复杂度。

posted @ 2023-07-30 02:23  purinliang  阅读(26)  评论(0编辑  收藏  举报