【tutte矩阵一般图匹配】1 or 2 -牛客20多校1I

转送门

题意是说给n个点m条边,能否选出一些边使得每个点恰好又d[i]个度。d[i]只有1或者2。

做法是每条边拆成x, y两个点,互连。边的两个点i拆成d[i]个点与x连,j拆成d[j]个点与y连。

然后做一般图匹配,判断是否有完美匹配。

关于tuttle矩阵

可以被证明,当x取模S域的随机数时,错误概率不会高于n/S

于是建起这个矩阵高斯消元即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
mt19937 mrand(random_device{}()); // mrand是给定随机数种子的的大随机数对象
int rnd(int x) { return mrand() % x;}
const double eps = 1e-6;
const int maxn = 433;
ll a[maxn][maxn];
ll mod = 1e9 + 7;
ll ksm(ll n, ll k)
{
    ll res = 1;
    while(k)
    {
        if(k & 1) res = res * n % mod;
        n = n * n % mod;
        k >>= 1;
    }
    return res;
}
int gauss(int n)
{
    int c, r;
    for (c = 0, r = 0; c < n; c ++ )
    {
        int t = r;
        for (int i = r; i < n; i ++ )
            if (a[i][c] != 0)
                t = i;

        if (a[t][c] == 0) continue;

        for (int i = c; i < n; i ++ ) swap(a[t][i], a[r][i]);
        //a[r][c] %= mod;
        ll inv = ksm(a[r][c], mod - 2);
        for (int i = n; i >= c; i -- ) a[r][i] = a[r][i] * inv % mod;

        for (int i = r + 1; i < n; i ++ )
                for (int j = n; j >= c; j -- )
                    a[i][j] = (a[i][j] - a[r][j] * a[i][c] % mod) % mod;

        r ++ ;
    }
    // for(int i = 0; i < n; i++)
    //     for(int j = 0; j < n; j++) printf("%d%c", a[i][j]," \n"[j == n - 1]);

    ll res = 1;
    for(int i = 0; i < n; i++) res = res * a[i][i] % mod;
    return res % mod;
}
int d[55], s[maxn];
int mp[55][55];
int main()
{
    int n, m; 
    while(~scanf("%d%d", &n, &m))
    {
        memset(mp, 0, sizeof mp);
        memset(a, 0, sizeof a);
        for(int i = 0; i < n; i++) scanf("%d", &d[i]);
        for(int i = 0; i < n; i++) s[i + 1] = s[i] + d[i];
        for(int i = 0; i < m; i++) 
        {
            int u, v; scanf("%d%d", &u, &v);
            u--, v--;
            mp[u][v] ++; mp[v][u]++;
        }

        for(int i = 0; i < n; i++)
            for(int j = i + 1; j < n; j++)
            {
                if(mp[i][j] == 0) continue;
                for(int k = 0; k < min(2, mp[i][j]); k++)
                {
                    ll rd = 0;
                    for(int l = 0; l < d[i]; l++)
                    {
                        rd = rnd(mod);
                        a[s[i] + l][s[n]] = rd;
                        a[s[n]][s[i] + l] = -rd; 
                    }
                    rd = rnd(mod);
                    a[s[n]][s[n] + 1] = rd;
                    a[s[n] + 1][s[n]] = -rd;
                    s[n] ++;
                    for(int r = 0; r < d[j]; r++)
                    {
                        rd = rnd(mod);
                        a[s[j] + r][s[n]] = rd;
                        a[s[n]][s[j] + r] = -rd;
                    }
                    s[n]++;
                }
            }
        // cerr << "\n------\n";
        // for(int i = 0; i < s[n]; i++)
        // for(int j = 0; j < s[n]; j++) printf("%d%c", a[i][j]," \n"[j == s[n] - 1]);
        // cerr << "\n------\n";
        if(gauss(s[n]) != 0) printf("Yes\n");
        else printf("No\n");

    }


}

发表评论

电子邮件地址不会被公开。 必填项已用*标注