优先队列bfs + 状态压缩
不难想到,最小团就是空集,我们可以向这个空集里加点,来找到k小团
具体做法就是用优先队列,把权值小的团出队,为了不重复加点,我们可以记录一下最后几个被加进团的点,这样下次直接从该点之后遍历,这样就可以把所有点都遍历一次了。
用bitset来保存点连接状态可以直接判断该点是否与团的每个点相连
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define full(a, b) memset(a, b, sizeof a)
#define FAST_IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
using namespace std;
typedef long long LL;
inline int lowbit(int x){ return x & (-x); }
inline int read(){
int ret = 0, w = 0; char ch = 0;
while(!isdigit(ch)){
w |= ch == '-', ch = getchar();
}
while(isdigit(ch)){
ret = (ret << 3) + (ret << 1) + (ch ^ 48);
ch = getchar();
}
return w ? -ret : ret;
}
inline int lcm(int a, int b){ return a / __gcd(a, b) * b; }
template <typename A, typename B, typename C>
inline A fpow(A x, B p, C lyd){
A ans = 1;
for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd;
return ans;
}
const int N = 200;
int n, k, val[N];
struct Node{
LL w;
int s;
bitset<105> clique;
bool operator < (const Node &rhs) const {
return w > rhs.w;
}
Node(){}
Node(LL w, int s, bitset<105> clique): w(w), s(s), clique(clique){}
};
bitset<105> e[N];
LL solve(){
priority_queue<Node> pq;
int cnt = 0;
bitset<105> raw;
raw.reset();
pq.push(Node(0, 0, raw));
while(!pq.empty()){
Node cur = pq.top(); pq.pop();
cnt ++;
if(cnt == k) return cur.w;
for(int i = cur.s + 1; i <= n; i ++){
if((e[i] & cur.clique) == cur.clique){
bitset<105> b(cur.clique);
b.set(i, 1);
pq.push(Node(cur.w + val[i], i, b));
}
}
}
return -1;
}
int main(){
n = read(), k = read();
for(int i = 1; i <= n; i ++) val[i] = read();
string s;
for(int i = 1; i <= n; i ++){
cin >> s;
for(int j = 1; j <= n; j ++){
e[i].set(j, s[j - 1] - '0');
}
}
printf("%lld
", solve());
return 0;
}