方格取数(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[][];
  8. int dp1[<<],before[<<],now[<<];
  9.  
  10. void prepare(int i,int n)//预处理
  11. {
  12. int j,k,s;
  13. k=<<n;
  14. for(j=; j<k; j++)
  15. {
  16. dp1[j]=;
  17. for(s=; s<=n; s++)
  18. {
  19. if( (j&(<<(s-))) == (<<(s-)) )//包含了这个数字
  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=;
  28. for(i=; i<n; i++)
  29. {
  30. if( (x&b) == x) return false;
  31. x=x<<;
  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=; i<=n; i++)
  42. for(j=; j<=n; j++)
  43. scanf("%d",&a[i][j]);
  44. memset(now,,sizeof(now));
  45. memset(before,,sizeof(before));
  46. k=<<n;
  47. for(i=; i<=n; i++)
  48. {
  49. prepare(i,n);
  50. for(j=; j<k; j++)
  51. if(panduan(j,n))
  52. {
  53. hxl=;
  54. for(s=; s<k; s++)
  55. {
  56. if( (s&j)> ) continue;
  57. if(before[s]>hxl)
  58. hxl=before[s];
  59. }
  60. dp1[j]=dp1[j]+hxl;
  61. }
  62. for(j=; j<k; j++)
  63. {
  64. now[j]=dp1[j];
  65. before[j]=now[j];
  66. }
  67. }
  68. hxl=;
  69. for(i=; i<k; i++)
  70. if(now[i]>hxl) hxl=now[i];
  71.  
  72. printf("%d\n",hxl);
  73. }
  74. return ;
  75. }

优化:

  很多地方可以优化。

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

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

   3.滚动数组。

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

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<string.h>
  4.  
  5. int a[][];
  6. int state[],len;
  7. int dp[<<],befor[<<];
  8.  
  9. void make_init()//预处理,所以的状态
  10. {
  11. int i,k;
  12. k=<<;
  13. len=;
  14. for(i=;i<k;i++)
  15. {
  16. if( (i&(i<<))> ) 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=<<n;
  24.  
  25. for(j=;state[j]<k;j++)
  26. {
  27. i=state[j];
  28. dp[i]=;
  29. x=i;
  30. ans=;
  31. while(x)
  32. {
  33. if(x&) dp[i]=dp[i]+a[r][ans];
  34. ans++;
  35. x=x>>;
  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)>)
  46. {
  47. for(i=;i<=n;i++)
  48. for(j=;j<=n;j++)
  49. scanf("%d",&a[i][j]);
  50.  
  51. k=<<n;
  52. memset(befor,,sizeof(befor));
  53. for(i=;i<=n;i++) //枚举每一行
  54. {
  55. prepare(i,n);
  56. for(j=;state[j]<k;j++)//枚举每一种 有效 状态
  57. {
  58. hxl=;
  59. for(s=;state[s]<k;s++)//上一行的有效状态
  60. {
  61. if( (state[j]&state[s]) >) 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=;state[j]<k;j++)
  68. {
  69. befor[state[j]]=dp[state[j]];
  70. }
  71. }
  72. hxl=;
  73. for(i=;state[i]<k;i++)
  74. if(hxl<befor[state[i]]) hxl=befor[state[i]];
  75. printf("%d\n",hxl);
  76. }
  77. return ;
  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[][];
  6. int state[],len;
  7. int dp[],befor[];
  8.  
  9. void make_init()//预处理,所以的状态
  10. {
  11. int i,k;
  12. k=<<;
  13. len=;
  14. for(i=;i<k;i++)
  15. {
  16. if( (i&(i<<))> ) 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=<<n;
  24.  
  25. memset(dp,,sizeof(dp));
  26. for(j=;state[j]<k;j++)
  27. {
  28. x=state[j];
  29. ans=;
  30. while(x)
  31. {
  32. if(x&) dp[j]=dp[j]+a[r][ans];//!!!哈哈。
  33. ans++;
  34. x=x>>;
  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)>)
  45. {
  46. for(i=;i<=n;i++)
  47. for(j=;j<=n;j++)
  48. scanf("%d",&a[i][j]);
  49.  
  50. k=<<n;
  51. memset(befor,,sizeof(befor));
  52. for(i=;i<=n;i++) //枚举每一行
  53. {
  54. prepare(i,n);
  55. for(j=;state[j]<k;j++)//枚举每一种 有效 状态
  56. {
  57. hxl=;
  58. for(s=;state[s]<k;s++)//上一行的有效状态
  59. {
  60. if( (state[j]&state[s]) >) continue;//没有冲突
  61. if(befor[s]>hxl)
  62. hxl=befor[s];
  63. }
  64. dp[j]=dp[j]+hxl;
  65. }
  66. for(j=;state[j]<k;j++)
  67. {
  68. befor[j]=dp[j];
  69. }
  70. }
  71. hxl=;
  72. for(i=;state[i]<k;i++)
  73. if(hxl<befor[i]) hxl=befor[i];
  74. printf("%d\n",hxl);
  75. }
  76. return ;
  77. }

hdu 1565 方格取数(1) 状态压缩dp的更多相关文章

  1. HDU 1565 - 方格取数(1) - [状压DP][网络流 - 最大点权独立集和最小点权覆盖集]

    题目链接:https://cn.vjudge.net/problem/HDU-1565 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32 ...

  2. HDU1565 方格取数(1)(状态压缩dp)

    题目链接. 分析: 说这题是状态压缩dp,其实不是,怎么说呢,题目数据太水了,所以就过了.手动输入n=20的情况,超时.正解是网络流,不太会. A这题时有个细节错了,是dp[i][j]还是dp[i][ ...

  3. 网络流(最大流) HDU 1565 方格取数(1) HDU 1569 方格取数(2)

      HDU 1565 方格取数(1) 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的 ...

  4. HDU 1565 方格取数(1) 轮廓线dp

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1565 方格取数(1) Time Limit: 10000/5000 MS (Java/Others) ...

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

    方格取数(1)                                                                 Time Limit: 10000/5000 MS (J ...

  6. hdu 2167 方格取数 【状压dp】(经典)

    <题目链接> 题目大意: 给出一些数字组成的n*n阶矩阵,这些数字都在[10,99]内,并且这个矩阵的  3<=n<=15,从这个矩阵中随机取出一些数字,在取完某个数字后,该数 ...

  7. HDU 1565 方格取数(简单状态压缩DP)

    http://acm.hdu.edu.cn/showproblem.php?pid=1565 对于每一个数,取或者不取,用0表示不取,1表示取,那么对于每一行的状态,就可以用一个二进制的数来表示.比如 ...

  8. HDU 1565 方格取数(1)(最大点权独立集)

    http://acm.hdu.edu.cn/showproblem.php?pid=1565 题意: 给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格 ...

  9. HDU 1565 方格取数 状压dp

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

随机推荐

  1. log4j日志+面向切面监控异常

    log4j.xml src/main/resources ----------------------------------------------------------------------- ...

  2. easyui里面的加载tree的两种方式

    第一种: 使用EasyUI中Tree 符合EasyUI中Tree的Json格式,我们先看一下,格式是如何的 [{ "id":1, "text":"My ...

  3. Ionic2使用百度地图API(JS)出现白屏解决方案

    最近自学ionic2,写了一个内嵌百度地图JS的demo,实际跑起来之后出现了大家常见的白屏问题.. 最初的实现是这样的: 首先主页内嵌了一个百度地图插件 <div id="Bmap& ...

  4. iOS中的自由桥接

    [摘抄自<iOS 6编程实战>] 与Objective-C库不同,我们在Objective-C中使用标准C语言和Core Foundation类库(CF*方法)不会遵循那些命名约定.这意味 ...

  5. P4383 [八省联考2018]林克卡特树lct 树形DP+凸优化/带权二分

    $ \color{#0066ff}{ 题目描述 }$ 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的 ...

  6. elasticsearch-sql插件

    elasticsearch DSL语法有些时候比较难懂换成SQL好处理一些,网上找到一个插件 https://github.com/NLPchina/elasticsearch-sql 安装elast ...

  7. 动手玩转Docker(二)

    CentOS7下安装docker: 通过命令uname -r 查看linux内核版本,版本低的话不支持docker. [tim@num root]$ uname -r 3.10.0-514.el7.x ...

  8. Kafka:Consumer

    1.预览 1.1 消费者组(Consumer Group) 一个consumer group可能有若干个consumer实例 同一个group里面,topic的每条信息只能被发送到group下的一个c ...

  9. [转] Jenkins pipeline 中获取 exit code, stdout and stderr 返回值和输出

    [From] https://issues.jenkins-ci.org/browse/JENKINS-44930 其做法是,把stdout定向到一个文件,sh 配置 returnStatus: tr ...

  10. FreeRTOS-05任务相关API函数

    根据正点原子FreeRTOS视频整理 单片机:STM32F207VC FreeRTOS源码版本:v10.0.1 任务相关API函数: 1. main.c /* * */ #include " ...