# 牛客多校第一场 带花树模板 I - 1 or 2

1 篇文章 0 订阅
1 篇文章 0 订阅

牛客多校第一场 带花树模板 I - 1 or 2

Face


题意

  • 给定一个有 n n n个节点, m m m条边的图,给定一个数组 d d d d [ i ] d[i] d[i]表示第i个节点恰好有 d [ i ] d[i] d[i]个匹配

数据范围: 1 ≤ n ≤ 60 , 1 ≤ m ≤ 100 , 1 ≤ d [ i ] ≤ 2 1\leq n \leq 60, 1 \leq m \leq 100 , 1 \leq d[i] \leq 2 1n60,1m100,1d[i]2


前置技能
  • 裸带花树
Tutorial:
复杂度: O ( n 3 ) O(n^3) O(n3)

code:



#include <bits/stdc++.h>

using namespace std;
#define _rep(n, a, b) for (ll n = (a); n <= (b); ++n)
#define _rev(n, a, b) for (ll n = (a); n >= (b); --n)
#define _for(n, a, b) for (ll n = (a); n < (b); ++n)
#define _rof(n, a, b) for (ll n = (a); n > (b); --n)
#define oo 0x3f3f3f3f3f3f
#define ll long long
#define db long double
#define eps 1e-3
#define bin(x) cout << bitset<10>(x) << endl;
#define what_is(x) cerr << #x << " is " << x << endl
#define met(a, b) memset(a, b, sizeof(a))
#define all(x) x.begin(), x.end()
#define pii pair<ll, ll>
#define pdd pair<db, db>
#define endl "\n"
const ll mod = 998244353;
const ll maxn = 2e3 + 10;
vector<int> G[maxn];

ll qpow(ll a, ll b) {
    ll ret = 1;
    for (; b; a = a * a % mod, b >>= 1) {
        if (b & 1) {
            ret = ret * a % mod;
        }
    }
    return ret;
}

vector<ll> f(maxn), invf(maxn);

ll inv(ll a) {
    return qpow(a, mod - 2);
}

void prework() {
    f[0] = 1;
    _rep(i, 1, maxn - 1) {
        f[i] = f[i - 1] * i % mod;
    }
    invf[maxn - 1] = qpow(f[maxn - 1], mod - 2);
    for (int i = maxn - 2; i >= 0; i--) {
        invf[i] = invf[i + 1] * (i + 1) % mod;
    }

}

ll C(ll n, ll m) {
    if (n > m || m < 0)return 0;
    if (n == 0 || m == n) return 1;
    ll res = (f[m] * invf[m - n] % mod * invf[n]) % mod;
    return res;
}

//带花树 一般图最大匹配
int n, m;
deque<int> Q;
bool g[maxn][maxn], inque[maxn], inblossom[maxn], inpath[maxn];
int match[maxn], pre[maxn], base[maxn];

int findancestor(int u, int v) {
    for (int i = 1; i <= n; i++)inpath[i] = 0;
    while (1) {
        u = base[u];
        inpath[u] = true;
        if (match[u] == -1)break;
        u = pre[match[u]];
    }
    while (1) {
        v = base[v];
        if (inpath[v])return v;
        v = pre[match[v]];
    }
}

void reset(int u, int anc) {
    while (u != anc) {
        int v = match[u];
        inblossom[base[u]] = 1;
        inblossom[base[v]] = 1;
        v = pre[v];
        if (base[v] != anc)pre[v] = match[u];
        u = v;
    }
}

void contract(int u, int v, int n) {
    int anc = findancestor(u, v);
    for (int i = 1; i <= n; i++)inblossom[i] = 0;
    reset(u, anc);
    reset(v, anc);
    if (base[u] != anc)pre[u] = v;
    if (base[v] != anc)pre[v] = u;
    for (int i = 1; i <= n; i++)
        if (inblossom[base[i]]) {
            base[i] = anc;
            if (!inque[i]) {
                Q.push_back(i);
                inque[i] = 1;
            }
        }
}

bool bfs(int S, int n) {
    for (int i = 0; i <= n; i++)pre[i] = -1, inque[i] = 0, base[i] = i;
    Q.clear();
    Q.push_back(S);
    inque[S] = 1;
    while (!Q.empty()) {
        int u = Q.front();
        Q.pop_front();
        for (int v = 1; v <= n; v++) {
            if (g[u][v] && base[v] != base[u] && match[u] != v) {
                if (v == S || (match[v] != -1 && pre[match[v]] != -1))contract(u, v, n);
                else if (pre[v] == -1) {
                    pre[v] = u;
                    if (match[v] != -1)Q.push_back(match[v]), inque[match[v]] = 1;
                    else {
                        u = v;
                        while (u != -1) {
                            v = pre[u];
                            int w = match[v];
                            match[u] = v;
                            match[v] = u;
                            u = w;
                        }
                        return true;
                    }
                }
            }
        }
    }
    return false;
}

bool solve() {
    for (int i = 1; i <= n; i++)match[i] = -1;
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (match[i] == -1 && bfs(i, n)) ans++;
    }
    return ans == n / 2;
}

int d[maxn], d1[maxn], l[maxn], r[maxn];
int u[maxn], v[maxn];

bool build() {
    memset(g, 0, sizeof g);
    memset(l, 0, sizeof l);
    int cnt = 0;
    for (int i = 1; i <= n; i++)
        if (d1[i] > d[i]) return 0;
    for (int i = 1; i <= m; i++) {
        if (!l[u[i]]) {
            l[u[i]] = ++cnt;
            r[u[i]] = d[u[i]] - d1[u[i]] + cnt - 1;
            cnt += d[u[i]] - d1[u[i]] - 1;
        }
        if (!l[v[i]]) {
            l[v[i]] = ++cnt;
            r[v[i]] = d[v[i]] - d1[v[i]] + cnt - 1;
            cnt += d[v[i]] - d1[v[i]] - 1;
        }
        int k = cnt + 2;
        cnt += 2;
        g[k][k - 1] = g[k - 1][k] = 1;
        for (int j = l[u[i]]; j <= r[u[i]]; j++)
            g[j][k] = g[k][j] = 1;
        for (int j = l[v[i]]; j <= r[v[i]]; j++)
            g[k - 1][j] = g[j][k - 1] = 1;
    }
    n = cnt;
    return 1;
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    while (cin >> n >> m) {
        met(d, 0);
        _rep(i, 1, n) {
            cin >> d1[i];
        }
        _rep(i, 1, m) {
            cin >> u[i] >> v[i];
            d[u[i]]++;
            d[v[i]]++;
        }
        if (build() && solve())
            cout << "Yes" << endl;
        else cout << "No" << endl;

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值