【題解】Shortest Cycle

原題連接:CF1205B
ios

題目大意

  給定\(n\)個整數\(a_1,a_2,a_3, \dots ,a_n\),若\(i \neq j\)\(a_i \land a_j \neq 0\),則節點\(i\)和節點\(j\)相連通。求最小環大小。
  \(1 \leq n \leq 10^5\)\(0 \leq a_i \leq 10^{18}\)spa

題解

  題目中的\(a_i\)都在long long的範圍內,即\(a_i \in [0, 2^{64})\),則根據容斥原理可得,若集合\(\{ a_i | a_i \neq 0 \}\)的大小\(n\)知足\(n > 128\),必定有節點數爲\(3\)的環。
  不然,跑一次Floyd求最小環便可。code

// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cstring>

#define MAX_N (130 + 5)

using namespace std;

int n;
long long a[MAX_N];
int w[MAX_N][MAX_N], dis[MAX_N][MAX_N];
int ans = 2000000000;

int main()
{
    scanf("%d", &n);
    long long tmp;
    for (int i = 1; i <= n; ++i)
    {
        scanf("%lld", &a[i]);
        if (!a[i]) --i, --n;
        if (i > 128) return printf("3"), 0;
    }
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= n; ++j)
        {
            if (i != j && (a[i] & a[j])) w[i][j] = 1;
            else w[i][j] = 100000000;
        }
    }
    memcpy(dis, w, sizeof w);
    for (int k = 1; k <= n; ++k)
    {
        for (int i = 1; i <= n; ++i)
        {
            for (int j = 1; j <= n; ++j)
            {
                if (i == k || i == j || j == k) continue;
                ans = min(ans, dis[i][j] + w[i][k] + w[k][j]);
            }
        }
        for (int i = 1; i <= n; ++i)
        {
            for (int j = 1; j <= n; ++j)
            {
                dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
            }
        }
    }
    if (ans > n) printf("-1");
    else printf("%d", ans);
    return 0;
}
相關文章
相關標籤/搜索