zoukankan      html  css  js  c++  java
  • 状态压缩模版2:选数

    这是第二道模版题,然后的话这道模版题其实和上一题

    这道题其实二进制的思想会体现的更加明显,因为的话我们一旦把我们需要的数转化成二进制之后,然后一个一个去判断,因为这种做法真的真的太神奇了,所以我觉得我讲不太通,就直接放代码吧

    所以直接看代码吧

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<iostream>
     7 using namespace std;
     8 int f[16][1<<15];/*状态压缩,二进制*/
     9 int a[16][16],v[1<<15],vn,bin[16],n;
    10 /*bin记录2的多少次方*/
    11 int main()
    12 {
    13     bin[1]=1;/*预处理,2的0次方*/
    14     for(int i=2;i<=15;i++) bin[i]=bin[i-1]<<1;/*预处理的就是2的多少次方*/
    15     scanf("%d",&n);
    16     for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&a[i][j]);
    17     int maxx=(1<<n)-1;/*2^n-1,位运算*/
    18     vn=0;/*每一行里面有多少种满足题目条件的数*/
    19     memset(f,0,sizeof(f));
    20     for(int x=0;x<=maxx;x++)/*包括不能用的,我也只有这么多种,我们可以拆成2进制,*/
    21     /*比如(1代表被选中的) 
    22     00001011000 向左一位
    23     00010110000 再&上面的,就是判断有没有重复的
    24     如果有重复的话返回的就是1,没有就是0 
    25     00000010000
    26     所以就证明这个有没有同时被选中
    27     又比如说
    28     00001001000 向左一位
    29     00010010000 再&上面的,就是判断有没有重复的
    30     00000000000 &后的结果
    31     所以说明这两个是不相交了,这样我们就可以说明他们两个是没有同时被选中的 
    32     */
    33     {
    34         if(((x<<1)&x)==0)/*判断相邻的两个有没有同时被选中*/
    35         {
    36             for(int i=1;i<=n;i++)/*每一行有n个*/
    37             {
    38                 if(bin[i]&x) f[1][x]+=a[1][i];
    39                 /*被选中的话,我们就把这个数的值加进f这个递归里面,
    40                 就是说x这个状态排列里面的总和是多少*/
    41             }
    42             v[++vn]=x;/*这是一种合法情况,所以我们就加进去,下面可以for一遍*/
    43         }
    44     }
    45     for(int i=2;i<=n;i++)/*第一行已经处理完了,所以从第二行开始*/
    46     {
    47         for(int p=1;p<=vn;p++)/*枚举每一种合法情况*/
    48         {
    49             int tt=0;
    50             for(int j=1;j<=n;j++) if(bin[j]&v[p]) tt+=a[i][j];
    51             /*
    52             把这种情况的总和加进tt里面,如果我们选了这种状态并且这种状态可以满足:
    53             1.相邻的两个没有同时被选中
    54             2.其他的八个相邻的方向都不能选中
    55             就加进去tt里面 
    56             */
    57             for(int q=1;q<=vn;q++)/*再for一遍,就是for我们的上一行是哪一种排列方式,
    58             我们现在是第二行,所以我们这里就是第一行*/
    59             {
    60                 if((v[p]&v[q])==0 && (v[q]<<1&v[p])==0 && (v[q]>>1&v[p])==0)
    61                 /*1.上面的那个数满足条件
    62                   2,3.并且上面的那个数的相邻两个也是没有被选中过的*/
    63                     f[i][v[p]]=max(f[i][v[p]],tt+f[i-1][v[q]]);
    64                     /*更新这个值,原来是f[i-1][v[q]]加上tt(现在这一行选中的数的值)
    65                     再和我之前的f[i][v[p]]比较哪个大*/
    66             }
    67         }
    68     }
    69     int ans=0;
    70     for(int i=1;i<=vn;i++) ans=max(ans,f[n][v[i]]);
    71     printf("%d
    ",ans);
    72     return 0;
    73 }
  • 相关阅读:
    [Python]jieba切词 添加字典 去除停用词、单字 python 2020.2.10
    假期学习【十一】Python切词,以及从百度爬取词典
    Cocos2D-x中关于CREATE_FUNC宏的用法
    Cocos2D-x中关于do{}while(0)和CC_BREAK_IF的用法
    Cocos2d-x学习笔记(三十三)之常用的宏
    Cocos2d-x学习笔记(三十二)之图片渲染
    Cocos2d-x学习笔记(三十一)之 内存管理
    Cocos2d-x学习笔记(三十)之 游戏存档
    Cocos2d-x学习笔记(二十九)之 声音
    Cocos2d-x学习笔记(二十八)之 滚动列表类CCListView
  • 原文地址:https://www.cnblogs.com/Tristanjiang/p/11458449.html
Copyright © 2011-2022 走看看