优先队列bfs + 状态压缩
不难想到,最小团就是空集,我们可以向这个空集里加点,来找到k小团
具体做法就是用优先队列,把权值小的团出队,为了不重复加点,我们可以记录一下最后几个被加进团的点,这样下次直接从该点之后遍历,这样就可以把所有点都遍历一次了。
用bitset来保存点连接状态可以直接判断该点是否与团的每个点相连
#include#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 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 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\n", solve()); return 0;}