牛客多校第二场 D
题目链接
大概意思就是给出无向图和点权求出第k小团。
我们首先得知道什么叫团:
维基百科解释:在图论领域的一个无向图中,满足两两之间有边连接的顶点的集合,被称为该无向图的团。
知道含义之后。这道题其实也很好做.一个基础的BFS,我们用二进制进行存图和存点,所以我们用bitset,存图是两点i,j可达那么f[i][j] = f[j][i] = 1,bfs时我们还是用二进制存点,走过的点为1没走过为0.
怎么给团进行扩大呢,我们知道&的用法,所以当团中的点与当前的点所存的可达的图&之后 仍然能够得到 原来的团,说明当前点和团中的结点都可达,所以我们可以把它加入团中。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef bitset<108> bs;
bs f[1003];
ll w[1005];
struct node{
ll ans;
bs x;
bool operator < (const node &a)const {
return ans > a.ans;
}
};
int main()
{
ll n,m;
cin >> n >>m;
for(int i = 1 ; i <= n; i ++){
cin >> w[i];
}
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++){
char c;
cin >> c;
if(c == '1') f[i][j] = 1;//存图
}
getchar();
}
bs t;
t.reset();
priority_queue <node> q;
q.push({0, t});
while(!q.empty()){
node now = q.top();
q.pop();
m -- ;
if(m == 0){
cout << now.ans << endl;
return 0;
}
int flag = 1;
for(int i = 1; i <= n; i ++){
if(now.x[i]){
flag = i + 1;
}
}
for(int i = flag ; i <= n; i ++){
if(!now.x[i] && (now.x & f[i]) == now.x){//判断是否可以加入团中/如果这个点没有被取过,并且,r为1的地方f[i]也为1,也就是意味着点i与r中的所有的节点都有连通,意味着加入点i后还是一个团,这样才符合题意。
node next = now;
next.x[i] = 1;
next.ans = now.ans + w[i];
q.push(next);
}
}
}
cout << -1 << endl;
}