hdu 1565 方格取数(1) 状态压缩dp

方格取数(1)

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3848    Accepted Submission(s): 1473


Problem Description
给你一个n*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。
 

 

Input
包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20)
 

 

Output
对于每个测试实例,输出可能取得的最大的和
 

 

Sample Input
3
75 15 21
75 15 28
34 70 5
 
Sample Output
188
 
Author
ailyanlu
 超内存,用滚动数组了,超时!
算一下时间复杂度 20*20*2^20*2^20 额额。。。。
 
超时代码留个标记
 1 #include<iostream>

 2 #include<cstdio>

 3 #include<cstdlib>

 4 #include<cstring>

 5 using namespace std;

 6 

 7 int a[21][21];

 8 int dp1[1<<21],before[1<<21],now[1<<21];

 9 

10 void prepare(int i,int n)//预处理

11 {

12     int j,k,s;

13     k=1<<n;

14     for(j=0; j<k; j++)

15     {

16         dp1[j]=0;

17         for(s=1; s<=n; s++)

18         {

19             if( (j&(1<<(s-1))) == (1<<(s-1)) )//包含了这个数字

20                 dp1[j]=dp1[j]+a[i][s];

21         }

22     }

23 }

24 bool panduan(int b,int n)

25 {

26     int i,x;

27     x=3;

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

29     {

30         if( (x&b) == x) return false;

31         x=x<<1;

32     }

33     return true;

34 }

35 int main()

36 {

37     int n;

38     int i,j,s,k,hxl;

39     scanf("%d",&n);

40     {

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

42             for(j=1; j<=n; j++)

43                 scanf("%d",&a[i][j]);

44         memset(now,0,sizeof(now));

45         memset(before,0,sizeof(before));

46         k=1<<n;

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

48         {

49             prepare(i,n);

50             for(j=0; j<k; j++)

51                 if(panduan(j,n))

52                 {

53                     hxl=0;

54                     for(s=0; s<k; s++)

55                     {

56                         if( (s&j)>0 ) continue;

57                         if(before[s]>hxl)

58                             hxl=before[s];

59                     }

60                     dp1[j]=dp1[j]+hxl;

61                 }

62             for(j=0; j<k; j++)

63             {

64                 now[j]=dp1[j];

65                 before[j]=now[j];

66             }

67         }

68         hxl=0;

69         for(i=0; i<k; i++)

70             if(now[i]>hxl) hxl=now[i];

71 

72         printf("%d\n",hxl);

73     }

74     return 0;

75 }

 

 优化:

  很多地方可以优化。

  1.其实,可以预处理相邻的情况。不要每一次都判断。就像打表一样。//怎么处理的呢?具体看一下代码。

  2.预处理相邻的情况后,发现,1<<20的数组,满足条件的只有17711种,这样的话,优化就巨大了。

    3.滚动数组。

      我的代码,还是不够优化的,960ms

     

 1 #include<stdio.h>

 2 #include<stdlib.h>

 3 #include<string.h>

 4 

 5 int a[22][22];

 6 int state[17715],len;

 7 int dp[1<<22],befor[1<<22];

 8 

 9 void make_init()//预处理,所以的状态

10 {

11     int i,k;

12     k=1<<20;

13     len=0;

14     for(i=0;i<k;i++)

15     {

16         if( (i&(i<<1))>0 ) continue;

17         else state[len++]=i;

18     }

19 }

20 void prepare(int r,int n)//处理每一行的dp值.

21 {

22     int i,j,k,ans,x;

23     k=1<<n;

24 

25     for(j=0;state[j]<k;j++)

26     {

27         i=state[j];

28         dp[i]=0;

29         x=i;

30         ans=1;

31         while(x)

32         {

33             if(x&1) dp[i]=dp[i]+a[r][ans];

34             ans++;

35             x=x>>1;

36         }

37     }

38 }

39 

40 int main()

41 {

42     int n;

43     int i,j,k,s,hxl;

44     make_init();

45     while(scanf("%d",&n)>0)

46     {

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

48         for(j=1;j<=n;j++)

49         scanf("%d",&a[i][j]);

50 

51         k=1<<n;

52         memset(befor,0,sizeof(befor));

53         for(i=1;i<=n;i++) //枚举每一行

54         {

55             prepare(i,n);

56             for(j=0;state[j]<k;j++)//枚举每一种 有效 状态

57             {

58                 hxl=0;

59                 for(s=0;state[s]<k;s++)//上一行的有效状态

60                 {

61                     if( (state[j]&state[s]) >0) continue;//没有冲突

62                     if(befor[state[s]]>hxl)

63                     hxl=befor[state[s]];

64                 }

65                 dp[state[j]]=dp[state[j]]+hxl;

66             }

67             for(j=0;state[j]<k;j++)

68             {

69                 befor[state[j]]=dp[state[j]];

70             }

71         }

72         hxl=0;

73         for(i=0;state[i]<k;i++)

74         if(hxl<befor[state[i]]) hxl=befor[state[i]];

75         printf("%d\n",hxl);

76     }

77     return 0;

78 }

 

进一步的优化:

  看了一下,别人的博客,看到一个很别人开的数组是很小的。why?

      我开的dp数组是 dp[1<<22],其实只要开dp[17715];和状态state[17715 ]一样就可以了.

为什么可以呢?

简单说明一下:原来的方法,是和最原始的位置是一一对应,所以,很好理解。

但是,有很多的空间是浪费的。

现在是对应状态一一对应,就是这样。这样数组开的就小很多了。而且速度快一些。

921ms  -->   486 ms

 1 #include<stdio.h>

 2 #include<stdlib.h>

 3 #include<string.h>

 4 

 5 int a[22][22];

 6 int state[17715],len;

 7 int dp[17715],befor[17715];

 8 

 9 void make_init()//预处理,所以的状态

10 {

11     int i,k;

12     k=1<<20;

13     len=0;

14     for(i=0;i<k;i++)

15     {

16         if( (i&(i<<1))>0 ) continue;

17         else state[len++]=i;

18     }

19 }

20 void prepare(int r,int n)//处理每一行的dp值.

21 {

22     int j,k,ans,x;

23     k=1<<n;

24 

25     memset(dp,0,sizeof(dp));

26     for(j=0;state[j]<k;j++)

27     {

28         x=state[j];

29         ans=1;

30         while(x)

31         {

32             if(x&1) dp[j]=dp[j]+a[r][ans];//!!!哈哈。

33             ans++;

34             x=x>>1;

35         }

36     }

37 }

38 

39 int main()

40 {

41     int n;

42     int i,j,k,s,hxl;

43     make_init();

44     while(scanf("%d",&n)>0)

45     {

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

47         for(j=1;j<=n;j++)

48         scanf("%d",&a[i][j]);

49 

50         k=1<<n;

51         memset(befor,0,sizeof(befor));

52         for(i=1;i<=n;i++) //枚举每一行

53         {

54             prepare(i,n);

55             for(j=0;state[j]<k;j++)//枚举每一种 有效 状态

56             {

57                 hxl=0;

58                 for(s=0;state[s]<k;s++)//上一行的有效状态

59                 {

60                     if( (state[j]&state[s]) >0) continue;//没有冲突

61                     if(befor[s]>hxl)

62                     hxl=befor[s];

63                 }

64                 dp[j]=dp[j]+hxl;

65             }

66             for(j=0;state[j]<k;j++)

67             {

68                 befor[j]=dp[j];

69             }

70         }

71         hxl=0;

72         for(i=0;state[i]<k;i++)

73         if(hxl<befor[i]) hxl=befor[i];

74         printf("%d\n",hxl);

75     }

76     return 0;

77 }

 

 

 

 

 

你可能感兴趣的:(HDU)