2019牛客多校第二场D-Kth Minimum Clique(优先队列+bitset)

Kth Minimum Clique

题目传送门

解题思路

我们可以从没有点开始,把点一个一个放进去,先把放入一个点的情况都存进按照权值排序的优先队列,每次在新出队的集合里增加一个新的点,为了避免重复,一个集合中的放入次序是按编号递增的,新放进去的点必须和已经在集合中的所有点之间都有一条边。当然我们不可能在入队时写两层循环来判断能不能放,所以用bitset,为1则说明集合里的点都和这个点之间有边,每次入队前利用&操作更新。

代码如下

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;

inline int read(){
    int res = 0, w = 0; char ch = 0;
    while(!isdigit(ch)){
        w |= ch == '-', ch = getchar();
    }
    while(isdigit(ch)){
        res = (res << 3) + (res << 1) + (ch ^ 48);
        ch = getchar();
    }
    return w ? -res : res;
}

const int N = 105;

ll v[N];
struct T{
    ll w;
    int x;
    bitset<N> bt;
    T(int x, ll w, bitset<N> bt): x(x), w(w), bt(bt){}
    bool operator<(const T& a)const{
        return w > a.w;
    }
};
bitset<N> bt[N];

int main()
{
    int n, k;
    n = read(), k = read();
    for(int i = 1; i <= n; i ++)
        scanf("%lld%*c", &v[i]);
    for(int i = 1; i <= n; i ++){
        for(int j = 1; j <= n; j ++){
            char ch = getchar();
            bt[i][j] = ch - '0';
        }
        getchar();
    }
    if(k == 1){
        cout << 0 << endl;
        return 0;
    }
    -- k;
    priority_queue<T> pq;
    for(int i = 1; i <= n; i ++)
        pq.push(T(i, v[i], bt[i]));
    while(!pq.empty()){
        T top = pq.top();
        pq.pop();
        -- k;
        if(k == 0){
            cout << top.w << endl;
            return 0;
        }
        int x = top.x;
        for(int i = x + 1; i <= n; i ++){
            if(top.bt[i])
                pq.push(T(i, top.w + v[i], top.bt & bt[i]));
        }
    }
    cout << -1 << endl;
    return 0;
}
posted @ 2019-07-23 17:24  whisperlzw  阅读(217)  评论(0编辑  收藏  举报