HDU 4281 Judges' response(状态压缩DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4281

题意:有n个点,编号0到n-1。每两个点之间有距离,每个点(除0外)遍历时有花费。在0点有好多人,每个人有m的时间去遍历。

第一问:问遍历完1到n-1用的最少人数?(不用考虑点与点之间的距离)

第二问:问怎么安排每个人遍历那些点可以使得所有人走的路程之和最小?(所有人从0出发最后要回到0点)

 

思路:

第一问直接状态压缩dp[state][pos]表示state状态下到达pos需要的最少人数?

第二问也是状态压缩,f[state][pos]表示state状态下到达pos的最少路程。

通过本题,第一学习了状态压缩用队列更好写,不用想太多;第二,用几个子集组成大的集合的时候,是这样写的:

k=(1<<n)-2;

for(i=1;i<(1<<n);i++,k--) if(ans[i]<INF)  for(j=k;j;j=(j-1)&k)

      ans[i|j]=min(ans[i|j],ans[i]+ans[j]);

 

 

#include <iostream>

#include <cmath>

#include <queue>

#include <cstring>

#include <cstdio>

#define INF 0x3f3f3f3f

#define P(x) ((x)*(x))

#define min(x,y) ((x)<(y)?(x):(y))

using namespace std;





int dp[(1<<16)+5][2];

int f[(1<<16)+5][20],dis[20][20],n,m,ans[(1<<16)+5],c[20];

int visit[(1<<16)+5][20],cost[(1<<16)+5];





void DP1()

{

    int i,j,k,visit[(1<<16)+5],x,y;

    queue<int> Q;



    memset(visit,0,sizeof(visit));

    memset(dp,-1,sizeof(dp));

    dp[1][0]=1;

    dp[1][1]=m;

    Q.push(1);

    visit[1]=1;

    while(!Q.empty())

    {

        k=Q.front();

        Q.pop();



        visit[k]=0;

        for(i=0;i<n;i++) if(!(k&(1<<i)))

        {

            j=k|(1<<i);

            if(dp[k][1]>=c[i]) x=dp[k][0],y=dp[k][1]-c[i];

            else x=dp[k][0]+1,y=m-c[i];

            if(dp[j][0]<0||dp[j][0]>x||dp[j][0]==x&&dp[j][1]<y)

            {

                dp[j][0]=x;

                dp[j][1]=y;

                if(!visit[j]) Q.push(j),visit[j]=1;

            }

        }

    }

    printf("%d ",dp[(1<<n)-1][0]);

}





void DP2()

{

    int i,j,k,t,state,pos;

    queue<int> Q;



    for(i=0;i<(1<<n);i++)

    {

        cost[i]=0;

        for(j=0;j<n;j++) if(i&(1<<j)) cost[i]+=c[j];

    }



    memset(visit,0,sizeof(visit));

    memset(f,-1,sizeof(f));

    f[0][0]=0;

    visit[0][0]=1;

    Q.push(0);



    while(!Q.empty())

    {

        k=Q.front();

        Q.pop();



        state=k%100000;

        pos=k/100000;

        visit[state][pos]=0;

        for(i=0;i<n;i++) if(!(state&(1<<i)))

        {

            k=state|(1<<i);

            t=f[state][pos]+dis[pos][i];

            if(cost[k]>m) continue;

            if(f[k][i]<0||f[k][i]>t)

            {

                f[k][i]=t;

                if(!visit[k][i])

                {

                    visit[k][i]=1;

                    Q.push(i*100000+k);

                }

            }

        }

    }



    memset(ans,INF,sizeof(ans));

    for(i=0;i<(1<<n);i++)  for(j=0;j<n;j++)

    {

        if(f[i][j]<0||!(i&(1<<j))||f[i][j]==INF) continue;

        ans[i]=min(ans[i],f[i][j]+dis[0][j]);

    }

    k=(1<<n)-2;

    for(i=1;i<(1<<n);i++,k--) if(ans[i]<INF) for(j=k;j;j=(j-1)&k)

        ans[i+j]=min(ans[i+j],ans[i]+ans[j]);

    printf("%d\n",ans[(1<<n)-1]);

}



int main()

{

    while(scanf("%d%d",&n,&m)!=-1)

    {

        int X[20],Y[20],i,j;

        for(i=0;i<n;i++) scanf("%d%d",&X[i],&Y[i]);

        for(i=0;i<n;i++) scanf("%d",&c[i]);

        for(i=0;i<n;i++) if(m<c[i]) break;

        if(i<n) {puts("-1 -1");continue;}

        for(i=0;i<n;i++) for(j=0;j<n;j++)

        {

            if(i==j) dis[i][j]=0;

            else dis[i][j]=ceil(sqrt(1.0*P(X[i]-X[j])+1.0*P(Y[i]-Y[j])));

        }

        DP1();

        DP2();

    }

    return 0;

}

 

  

 

你可能感兴趣的:(response)