小团拓展出的新团一定比大团拓展出的新团要小,因此可以使用优先队列搜索。
在寻找可拓展点的时候,可以使用位运算来优化,如果当前团的点集是找到点出边的子集,就可以拓展团。
每个团找拓展点的时候只找比最后入团的点编号大的,不回头找(回头找会拓展出重复的团)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 105;
int n, k, w[maxn];
struct node {
int id;
ll val;
bitset<maxn> u;
friend bool operator<(node a, node b) {
return a.val > b.val;
}
};
bitset<maxn> g[maxn], t;
char s[maxn];
int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; ++i) {
scanf("%d", &w[i]);
}
for (int i = 1; i <= n; ++i) {
scanf("%s", s + 1);
for (int j = 1; j <= n; ++j) {
g[i][j] = s[j] - '0';
}
}
priority_queue<node> q;
q.push({0, 0, t});
while (!q.empty()) {
node e = q.top();
q.pop(), --k;
if (k == 0) {
printf("%lld\n", e.val);
return 0;
}
for (int i = e.id + 1; i <= n; ++i) {
if (e.u[i]) {
continue;
}
if ((e.u & g[i]) == e.u) {
e.u[i] = 1;
q.push({i, e.val + w[i], e.u});
e.u[i] = 0;
}
}
}
printf("-1\n");
return 0;
}