题目链接
对于每一个点,至多有一个没有确定的点,可以确定兔子的位置。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;
#define LL __int64
#define cl(a,b) memset(a,b,sizeof(a))
#define pb push_back
const int maxn = 16;
const int inf = 1<<25;
const __int64 mod = 1000000007;
int edge[maxn*10];//使用二进制存边f[x]|=1<<y;多条边的信息
int dp[1<<maxn];//表示到达状态i的最小步数,i状态的1表示这个点已经确定
/*
*解法的可能,对于某一点,要么相邻的点全部是确定的,要么只有一个没有确定
*/
queue<int>q;
int main(){
int T;scanf("%d",&T);
while(T--){
int n,m;scanf("%d%d",&n,&m);
cl(edge,0);
for(int i=0;i<=(1<<n);i++)dp[i]=inf;
for(int i=0;i<m;i++){
int x,y;scanf("%d%d",&x,&y);x--;y--;//编号从0开始
edge[x]|=1<<y;
edge[y]|=1<<x;
}
//找到孤立点,自身连边
for(int i=0;i<n;i++)if(!edge[i])edge[i]=1<<i;
q.push(0);dp[0]=0;
while(!q.empty()){
int x=q.front();q.pop();
//找出当前集合x可以到达的所有点的集合cur
int cur=0;
for(int i=0;i<n;i++)if((x&edge[i])==edge[i])cur|=1<<i;
for(int i=0;i<n;i++)for(int j=i+1;j<n;j++)if(dp[cur|(1<<i)|(1<<j)]>dp[x]+1){
dp[cur|(1<<i)|(1<<j)]=dp[x]+1;
q.push(cur|(1<<i)|(1<<j));
}
}
int all = (1<<n)-1;
int ans = dp[all];//第一种情况,这个点相邻的点全部确定了
for(int i=0;i<n;i++)ans=min(ans,dp[all^(1<<i)]);//第二种可能,这个点,相邻的点只有一个没有确定
printf("%d\n",ans==inf?-1:ans);
while(!q.empty())q.pop();
}
return 0;
}