zoukankan      html  css  js  c++  java
  • 牛客网多校训练第二场D Kth Minimum Clique

    链接:https://ac.nowcoder.com/acm/contest/882/D
    来源:牛客网

    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.

    题意:给定一个无向图领接矩阵,每个点有权值,找出权值第k小的团的权值(一个团就是图的一个完全子图)

    解题思路:显然的,我们可以知道最小的团就是那个空的完全图,也就是0阶完全子图,由此启发,我们可以从这个最小的团生成第二小,第三小...的团,因为第二小,第三小...的团是由这个空团加入点生成的,这里很明显是一种广度优先搜索的思路

    但是,我们如何使得每次出队的团都是按照第n小,第n+1小这样的顺序来呢?很明显,由于每个点有权值,而团的大小的定义是点的权值和大小,并不是点的个数,因此这个地方,我们用优先队列实现,

    小团优先出队列,这样将可以保证出队的团的顺序是按照团的大小顺序,由小到大,因为每个团生成新的团一定会更大,所以第n次出队时堆顶的团一定是第n小的团,模拟这个BFS过程我们就可以得到第k小的团。

    PS:这个题通过bitset表示团和每个点所连接的所有点,实现优化

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n,k;
    ll val[105];
    bitset<105> sta[105];//状态压缩,表示i相连的所有点
    struct node
    {
        ll w;
        int id;//记录当前团最后加入的点编号,当前团只加入最后加入点之后的点,达到去重的目的
        bitset<105> clique;
        friend bool operator<(const node& a,const node&b)
        {
            return a.w>b.w;
        }
    };
    priority_queue<node>q;
    int main() {
        cin >> n >> k;
        for (int i = 1; i <= n; i++) {
            cin>>val[i];
        }
        int x;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++) {
                scanf("%1d",&x);
                sta[i][j]=x;
            }
        ll ans=-1;
        node st;
        st.id=0;
        st.w=0;
        q.push(st);
        while (!q.empty())
        {
            node now = q.top();
            q.pop();
            k--;
            if(!k)
            {
                ans=now.w;
                break;
            }
            for(int i=now.id+1;i<=n;i++)
            {
                if((now.clique&sta[i])==now.clique)//说明点i与当前团中的点都相连
                {
                    node next;
                    next.id=i;
                    next.clique=now.clique;
                    next.clique[i]=1;
                    next.w=now.w+val[i];
                    q.push(next);
                }
            }
        }
        cout<<ans<<endl;
        return 0;
    }
    

    总结:这个题的本质是把DFS找最大团的过程解析出来,通过优先队列维护得到的团,获得第k小的团。

  • 相关阅读:
    第三章,DNA序列的进化演变
    哈迪-温伯格定律和近亲杂交
    mysql
    Dajngo admin使用
    Django之Form组件
    python三大器
    python函数
    python文件操作
    python字典和集合
    算法基础
  • 原文地址:https://www.cnblogs.com/xusirui/p/11221952.html
Copyright © 2011-2022 走看看