题目链接: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); } }