题解:CF906C Party
鉴定为:紫不如蓝。
这是一道经典的状压 dp,dp 转移的过程非常好想,设
一种是枚举它的补集,然后把贡献加进去,但是这样做时间复杂度会太高,所以不行。
还有一种是经典套路,就是枚举一个已经加入的朋友,通过它来找新加入的朋友。设
还有就是 dfs 的过程,对于可以产生贡献的
然后你就会发现,样例过不了。
但是我们发现,最后的集合都一样,因为这是一个无向图,让谁先认识都一样,中间都是联通的。所以我们正向输出和倒向输出都对。
源代码:
#include<bits/stdc++.h>
#define int long long
#define INF 0x3f3f3f3f
using namespace std;
int n,m,f[1<<22],g[22],fa[(1<<22)],s[(1<<22)],ans[(1<<22)];
int nxt[22];
vector<int> t[22];
void dfs(int now){
if(fa[now])dfs(fa[now]);
cout<<ans[now]<<" ";
}
signed main(){
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=0;i<(1<<n);i++){
f[i]=INF;
}
for(int i=0;i<n;i++)g[i]|=(1<<i);
for(int i=1;i<=m;i++){
int a,b;cin>>a>>b;
t[a-1].push_back(b-1);
t[b-1].push_back(a-1);
g[a-1]|=(1<<(b-1));
g[b-1]|=(1<<(a-1));
}
if((n*(n-1)/2)==m){
cout<<0;return 0;
}
for(int i=0;i<n;i++){
f[g[i]]=1;
ans[g[i]]=i+1;
}
for(int i=0;i<(1<<n);i++){
if(f[i]==INF)continue;
for(int j=0;j<n;j++){
if(!(i&(1<<j)))continue;
if(f[i]+1<f[i|g[j]]){
f[i|g[j]]=f[i]+1;
fa[i|g[j]]=i;
ans[i|g[j]]=j+1;
}
}
}
cout<<f[(1<<n)-1]<<endl;
dfs((1<<n)-1);
}