CodeForces - 906C Party 【状压dp】
我们通过状态压缩,然后判断转移的情况,然后主要通过| 的运算,将不是联通块中的人的朋友加入到联通块中的操作
#include <bits/stdc++.h>
#define cl(a) memset(a,0,sizeof(a))
#define ll long long
#define pb(i) push_back(i)
#define mp make_pair
using namespace std;
const int maxn=2e5+50;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
typedef pair<int,int> PII;
ll fpow(ll n, ll k, ll p = mod) {ll r = 1; for (; k; k >>= 1) {if (k & 1) r = r * n%p; n = n * n%p;} return r;}
ll inv(ll a, ll p = mod) {return fpow(a, p - 2, p);}
//head
int conn[22];
int dp[1<<(22+1)][3];
int main()
{
int n,m,i,j;
scanf("%d %d",&n,&m);
for(int i=0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
u--;v--;
conn[u] |= 1<<v;
conn[v] |= 1<<u; //记录每个点相连的边的情况
}
for(int i=0;i<n;i++) conn[i]|=(1<<i);
memset(dp,0x3f,sizeof(dp));
for(i=1;i<(1<<n);i++)
{
for(j=0;j<n;j++)
{
int t=i & (1<<j);
if(!t){
continue;
} //在第i种联通块中,不包含编号为j的人的情况
if((conn[j]&i)!=i) break;// 也就是说找到了一个人j ,在i中,并且i中有的人不是j的朋友
}
if(j>=n) dp[i][0]=0; //所有在i中的人自己形成了一个完全图。
for(j=0;j<n;j++)
{
if(!(i&(1<<j)))continue; // i中不包含编号为j的人,就跳过
int x = i | conn[j]; //否则的话,就把j的朋友加到联通块中
if(dp[x][0]>dp[i][0]+1) //从i到j的一个转移,dp[][1] 保存原始状态,dp[][2]保存选的人
{
dp[x][0]=dp[i][0]+1;
dp[x][1]=i;
dp[x][2]=j;
}
}
}
int x = (1<<n)-1;
printf("%d\n",dp[x][0]);
vector<int>ve;
while(dp[x][0])
{
ve.push_back(dp[x][2]);
x=dp[x][1];
}
int ed = ve.size()-1;
for(int i=ed;i>=0;i--)
{
printf("%d ",ve[i]+1);
}
return 0;
}