欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

题解 | Kth minimum Clique-2019牛客暑期多校训练营第二场D题

程序员文章站 2022-04-01 13:03:53
...

题目来源于牛客竞赛:https://ac.nowcoder.com/acm/contest/discuss
题目描述:
Given a vertex-weighted graph with N vertices, find out the K-th minimum weighted clique.

A subset of vertices of an undirected graph is called clique if and only if every two distinct vertices in the subset are adjacent. The weight of a clique is the summation of the weight of vertices in it.

输入描述:
The first line of input contains two space-separated integers N, K.
The second line of input contains N space-separated integers wi representing the weight of each vertex.
Following N lines each contains N characters eij. There’s an edge between vertex i and vertex j if and only if eij= “1”.

1≤N≤100
1≤K≤106
0≤wi≤109
eij∈“01”
eii=0
eij=eji

输出描述:
Output one line containing an integer representing the answer. If there’s less than K cliques, output “-1”.

示例1:
输入
2 3
1 2
01
10

输出
2

说明
An empty set is considered as a clique.

题解:
• Brute force, bitmask
We just need to brute force!
By maintaining the current clique, potential new vertex to add, and current weight sum, we can find out next possible clique in O(1)!.

• Brute force, bitmask
By maintaining the current clique, potential new vertex to add, and current weight sum, we can find out next possible clique in O(1)!.
By extracting out the lowest bit of potential set(maintaining in bitmask), we can either construct another valid clique(Yeah!) or found that sum of weights exceeds V. Thus, for each clique, we will either find out another clique or stop searching in O(1). We only need to find out at most K cliques for each V. Results in an O(K \lg MAXV) solution.

• Brute force, bitmask
First, let sort all the vertice by their weight.
Then, binary search the answer V.
We need to find out whether there are K or more or less cliques with value <= V.
We just need to brute force!

代码:

// Author: Yen-Jen Wang
#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

typedef long long ll;

const __int128 ONE = 1;
const int MAX_N = 100 + 7;

int N, K;
int W[MAX_N];
vector<int> odr;
__int128 G[MAX_N];
char S[MAX_N][MAX_N];

void input() {
    scanf("%d%d", &N, &K);
    for (int i = 0; i < N; i++) 
        scanf("%d", &W[i]);
    for (int i = 0; i < N; i++) {
        scanf("%s", S[i]);
        for (int j = 0; j < N; j++)
            S[i][j] -= '0';
    }
}

int popcount(__int128 x) {
    return __builtin_popcountll(x >> 50) + __builtin_popcount(x & ((ONE << 50) - 1));
}

int lowbit(__int128 x) {
    if ((x & ((ONE << 50) - 1)) == 0)
        return __builtin_ctzll((ll)(x >> 50)) + 50;
    else
        return __builtin_ctzll((ll)(x & ((ONE <<50) - 1)));
}

void build() {
    for (int i = 0; i < N; i++)
        odr.push_back(i);
    sort(odr.begin(), odr.end(), [&] (const int x, const int y) {
        return W[x] < W[y];
    });

    static int mapping[MAX_N];
    for (int i = 0; i < N; i++)
        mapping[odr[i]] = i;

    static int W_tmp[MAX_N];
    for (int i = 0; i < N; i++)
        W_tmp[i] = W[i];
    for (int i = 0; i < N; i++) 
        W[mapping[i]] = W_tmp[i];
    
    static char S2[MAX_N][MAX_N];
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) 
            S2[i][j] = S[i][j];
    }
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) 
            S[mapping[i]][mapping[j]] = S2[i][j];
    }
    for (int i = 0; i < N; i++) {
        G[i] = 0;
        for (int j = 0; j < N; j++) {
            if (S[i][j]) {
                G[i] |= (ONE << j);
            }
        }
    }
}

int cnt;
ll limit;

void dfs(__int128 now, __int128 can, ll sum) {
    if (sum <= limit)
        cnt++;
    else
        return;
    
    if (cnt >= K)
        return;

    while (can) {
        int p = lowbit(can);
        can ^= (ONE << p);

        dfs(now | (ONE << p), can & G[p], sum + W[p]);

        //if ((now & G[p]) != now)
            //continue;
        
        if (sum + W[p] > limit)
            break;
        
        //dfs(now | (ONE << p), can, sum + W[p]);
        
        if (cnt >= K)
            break;
    }
}

bool check(ll x) {
    cnt = 0;
    limit = x;
    dfs(0, (ONE << N) - 1, 0);
    return cnt >= K;
}

void solve() {    
    ll lb = 0, rb = 0;
    for (int i = 0; i < N; i++)
        rb += W[i];
    while (lb < rb) {
        ll mid = (lb + rb) >> 1;
        if (check(mid))
            rb = mid;
        else
            lb = mid + 1;
    }
    if (check(lb))
        printf("%lld\n", lb);
    else
        puts("-1");
}

int main() {
    input();
    build();
    solve();
    return 0;
}

更多问题,更详细题解可关注牛客竞赛区,一个刷题、比赛、分享的社区。
传送门:https://ac.nowcoder.com/acm/contest/discuss