設 \(f_i\) 表示第 \(i\) 個人知道的咒語集合,\(c_i\) 為其補集,那麼第 \(i\) 個人第 \(k\) 天會離開當且僅當存在一個序列 \(a_{1\sim k-1}\),使得 \(\bigcup\limits_{j=1}^{k-1}(f_i \cup f_{a_j})=\varnothing\),即 \(\bigcap_{j=1}^{k-1}(c_i \cap c_{a_j})=\text{U}\)。
考慮連線 \((a_i,b_i)\),那麼第一次有人沒來聚會的天數為最小點覆蓋數 \(k\)(選取最少的點使得它們能覆蓋圖中所有的邊),第 \(i\) 個人第 \(k\) 天會離開當且僅當存在一種最小點覆蓋方案使得選擇了節點 \(i\),注意到如果不選一個點就一定會選擇它的所有鄰居,搜尋時可以優先選擇度數最大的點進行操作,若此點度數不大於 \(2\) 而會使時間複雜度錯誤,但此時原圖一定由若干環或鏈組成,根據奇偶性直接判斷即可,複雜度為 \(T(k)=T(k-1)+T(k-3) \approx 10^5\)。
#include<bits/stdc++.h>
using namespace std;
int t,n,m,k,a,b,sum,cnt,ans[1001],vis[1001],use[1001],aus[1001];
set <int> G[1001];
basic_string <int> S;
void loop(int x){
use[x]=1,S+=x;
for(int y:G[x]) if(!use[y]) loop(y);
}
void dfs(int v){
if(v>k) return;
int d=1,w=0;
for(int i=1;i<=n;i++) if(G[i].size()>G[d].size()) d=i;
if(G[d].size()<=2){
int now=v;
for(int i=1;i<=n;i++) use[i]=0,aus[i]=vis[i];
for(int i=1;i<=n;i++){
if(!use[i]&&G[i].size()==1){
S.clear(),loop(i),now+=S.size()/2;
if(S.size()&1) for(int j=1;j<S.size()-1;j+=2) aus[S[j]]=1;
else for(int j:S) aus[j]=1;
}
}
for(int i=1;i<=n;i++){
if(!use[i]&&G[i].size()>1){
S.clear(),loop(i),now+=(S.size()+1)/2;
for(int j:S) aus[j]=1;
}
}
if(now<=k){
if(now<sum) sum=now,memset(ans,0,sizeof(ans));
if(now==sum) for(int i=1;i<=n;i++) ans[i]|=aus[i];
}
return;
}
vector <pair<int,int>> now;
for(int i:G[d]) now.push_back({i,d}),G[i].erase(d);
G[d].clear(),vis[d]=1,dfs(v+1),vis[d]=0;
for(auto [u,v]:now) G[u].insert(v),G[v].insert(u);
now.clear(),w=G[d].size(),S.clear();
for(int i:G[d]) S+=i;
for(int i:S) for(int j:G[i]) now.push_back({i,j}),G[j].erase(i);
for(int i:S) vis[i]=1,G[i].clear();
dfs(v+w);
for(auto [u,v]:now) G[u].insert(v),G[v].insert(u);
for(int i:G[d]) vis[i]=0;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&n,&m,&k),cnt=0,sum=1e9;
for(int i=1;i<=n;i++) G[i].clear(),ans[i]=0;
for(int i=1;i<=m;i++) scanf("%d%d",&a,&b),G[a].insert(b),G[b].insert(a);
dfs(0);
if(sum==1e9) printf("-1\n");
else{
for(int i=1;i<=n;i++) cnt+=ans[i];
printf("%d %d\n",sum,cnt);
for(int i=1;i<=n;i++) if(ans[i]) printf("%d ",i);
printf("\n");
}
}
return 0;
}