题目链接:http://acm.fzu.edu.cn/problem.php?pid=2093
题意:有n个点和m条相连的边,兔子可能藏在任一点钟,1秒可以询问2个点是否有兔子,兔子每1秒必须向相邻的点移动,问至少要多少秒才可以确定兔子的位置
思路:完全没想到是dp…当通向一个点的所有点都被确保没有兔子的话,即可确认该点没有兔子,01串来表示需要确认该点没有兔子的话需哪几个点被确认,压缩成10进制数后用F[i]来保存,dp[last]的last表示被已确认点,F[i]&last==F[i]代表第i个点可被确认,用now更新被确认的点(last中被确认过的点可能在now中不被确认),用队列保存now继续更新,因为剩下最后一个点没被确认时也能判断出兔子的位置,答案不一定是dp[(1<<n)-1];
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define inf 0x3f3f3f3f
#define maxn 1<<16
using namespace std;
int f[maxn],dp[maxn];
queue <int>que;
int main()
{
int t,n,m;
scanf("%d",&t);
while (t--)
{
scanf("%d%d",&n,&m);
memset(f,0,sizeof(f));
memset(dp,inf,sizeof(dp));
dp[0]=0;
while (!que.empty())
que.pop();
for (int i=0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
f[u-1]|=1<<(v-1);
f[v-1]|=1<<(u-1);
}
for (int i=0;i<n;i++)
if (!f[i]) f[i]=1<<i;
que.push(0);
while (!que.empty())
{
int last=que.front(),now=0;
que.pop();
for (int i=0;i<n;i++) if ((last&f[i])==f[i]) now|=1<<i;
for (int i=0;i<n;i++)
{
for (int j=i+1;j<n;j++)
{
if (dp[now|(1<<i)|(1<<j)] > dp[last]+1)
{
dp[now|(1<<i)|(1<<j)]=dp[last]+1;
que.push(now|(1<<i)|(1<<j));
}
}
}
}
int tmp=(1<<n)-1,res=dp[tmp];
for (int i=0;i<n;i++)
res=min(res,dp[tmp^(1<<i)]);
if (res==inf)
printf("%d\n",-1);
else
printf("%d\n",res);
}
}