状态压缩模版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\n",ans);
72     return 0;
73 }

猜你喜欢

转载自www.cnblogs.com/Tristanjiang/p/11458449.html