FZU 2093 寻找兔子 (状压dp)

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


你可能感兴趣的:(dp,ACM)