状态压缩DP----HDU4049 Tourism Planning

     状态压缩动态规划感觉都不是那么好写,看网上的人说这题是2011年ACM/ICPC中的水题,暗地里感觉很是惭愧啊(花了将近4个小时),结果还算是勉勉强强地弄出来了。

    与往常一样,先说说题目的意思和思路,再给出代码,最后分享出代码比较精髓的地方(有的话),另这随笔主要目的是方便自己以后使用,当然很是欢迎大家指出错误和批评。那就开始了:

   题目说的是有一群小伙伴去旅游,某个人对某以特定的城市有一定的兴趣,并且多人一同去还有奖励,当然门票还是要的嘛。

  输入:N(小伙伴的个数),M(城市的个数)紧接着的一行是各个城市的门票价格,然后是一个N*M的矩阵表示第i名游客对j城市的感兴趣度,最后还有一个N*N的矩阵表示若i旅客与j旅客结伴出行的话可以得到的奖金。特别注意的是游客可以中间插入,也可以中途离开,但若是中途离开以后就不得在后面的观光中出现.

  输出:最后的结果若<=0,那么就输出"STAY HOME"。

   思路还是状态压缩嘛,具体来讲就是用一个叫DP[i]的数组记录从开始的城市到当前城市中总共值中选出最大的,在用一个temp[i]数组来保存相应的DP[i]值,为后面的DP做准备,然后交替进行,期间必须保证离队以后的人不可以再次入队,这点怎么保证呢?

   for(int i=1;i<=M;i++)
    {
        for(int j=0;j<bit;j++) dp[j]=MIN;
        for(int j=0;j<bit;j++)
        {
            int weight=calculate(j,i);
            for(int k=j;k<bit;k=(k+1)|j)
            {
                dp[j]=max(dp[j],temp[k]+weight);
            }
        }
        for(int j=0;j<bit;j++) temp[j]=dp[j];
    }

就用这几行代码就可以搞定了。第一个for循环是从1到M的城市,第二行是对于城市i的状态为j,第三行是总结出从1到i可以达到的最大值,中间的temp一直记录这些最大值,这与滚动数组非常类似。为什么这样写就能保证中途掉队的的在以后就一定加不进来呢?那么你可以仔细看看第三个for循环k是如何增加的(k=(k+1)|j)保证了变化后的k中一定包含有j的状态,也就是说参观第i-1座城市的人一定>=参观i城市时候的人,并且i城市的人在i-1城市的一定有,然后大家可以用类似于归纳法的思想来证明这种思路是正确的。

  不罗嗦了,直接上代码:

    

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 
 5 using namespace std;
 6 #define INFI (1<<10)+20
 7 #define MIN -2139062144
 8 int N,M;
 9 int dp[INFI],bonus[12][12],cost[12];
10 int inter[12][12],temp[INFI];
11 
12 inline int max(int a,int b)
13 {
14     if(a>b) return a;
15     return b;
16 }
17 int calculate(int k,int v)
18 {
19     int sieze[12],num=0,result=0;
20     for(int i=0;i<N;i++) if(k&(1<<i)) sieze[++num]=i;
21     for(int i=1;i<=num;i++)
22     {
23         result+=inter[sieze[i]][v];
24         for(int j=i+1;j<=num;j++) result+=bonus[sieze[i]][sieze[j]];
25     }
26     return result-num*cost[v];
27 }
28 int DP()
29 {
30     int bit=1<<N;
31     for(int i=0;i<bit;i++) temp[i]=0;
32     for(int i=1;i<=M;i++)
33     {
34         for(int j=0;j<bit;j++) dp[j]=MIN;
35         for(int j=0;j<bit;j++)
36         {
37             int weight=calculate(j,i);
38             for(int k=j;k<bit;k=(k+1)|j)
39             {
40                 dp[j]=max(dp[j],temp[k]+weight);
41             }
42         }
43         for(int j=0;j<bit;j++) temp[j]=dp[j];
44     }
45     int result=-1;
46     for(int i=0;i<bit;i++) result=max(result,temp[i]);
47     if(result<=0) printf("STAY HOME.\n");
48         else printf("%d\n",result);
49 }
50 int main()
51 {
52 
53    while(scanf("%d %d",&N,&M),(N||M))
54    {
55        for(int i=1;i<=M;i++)
56         scanf("%d",&cost[i]);
57 
58        for(int i=0;i<N;i++)
59         for(int j=1;j<=M;j++)
60            scanf("%d",&inter[i][j]);
61 
62         for(int i=0;i<N;i++)
63             for(int j=0;j<N;j++)
64             scanf("%d",&bonus[i][j]);
65 
66         DP();
67    }
68 
69     return 0;
70 }

  

      

posted on 2014-08-14 15:24  沐曦枫,梦莲  阅读(427)  评论(0编辑  收藏  举报

导航