group 状压dp

Posted hzoi-cbx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了group 状压dp相关的知识,希望对你有一定的参考价值。

  应某些人要求,我把标签删掉了

  这是一道好题。

  一看$c<=16$果断状压,但是怎么压?

  一个很显然的思路是,枚举上下两层的状态,每一层的状态极限有$C(c,c/2)$,c=16的时候有13000左右,显然是死掉了。

  我们考虑换个角度。上下两层的状态数太多,那我们不妨只考虑一层,而每个点只与它上下左右四个点有关,在dp的时候也只需要考虑上面和左边的数,多余的点在转移完右边和下边之后就失去了用处,那么我们不妨扔掉它们。

  想到这个之后这道题就比较简单了。

  我们令$f[i][j][k]$表示当前考虑第i行第j个位置,状态为k时候的状态数,转移思路和插头dp有些类似,考虑当前格上面和左边是否有字母转移即可

  这道题很多思路都和插头dp有些相近的地方。

  理论复杂度$O(rc2^c)$,实际则远远达不到(达到了复杂度也是对的)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int r,c,cur,la,ans;
 4 char s[130][55];
 5 struct hash_map
 6     int fi[23333],ne[6000005];
 7     int val[6000006],tot,f[6000005];
 8     inline void clear()
 9         tot=0;memset(fi,0,sizeof(fi));
10     
11     inline int &operator [](int x)
12         int y=x%23333,i=fi[y];
13         for(;i&&val[i]!=x;i=ne[i]);
14         if(!i) ne[++tot]=fi[y],fi[y]=i=tot,val[tot]=x,f[i]=0;
15         return f[i];
16     
17 g[2];
18 inline int count(int x,int y)
19     int cnt=0;
20     for(int i=0;i<y;i++) cnt+=((x&2)>>1),x>>=1;
21     return cnt;
22 
23 inline int count2(int x,int y)
24     int cnt=0;
25     for(int i=c;i>=y;i--)
26         if(x&(1<<i)) cnt++;
27     return cnt;
28 
29 int main()
30     cin>>r>>c;
31     for(int i=1;i<=r;i++) scanf("%s",s[i]+1);
32     g[0][0]=0;
33     for(int i=1;i<=r;i++)
34         int len=strlen(s[i]+1),lea=strlen(s[i-1]+1);
35         for(int j=1;j<=c;j++)
36             la=cur,cur^=1;g[cur].clear();
37             for(int k=1;k<=g[la].tot;k++)
38                 int v=g[la].val[k],f=g[la].f[k],c1=count(v,j-1),c2=lea-count2(v,j)+1;
39                 if(len-c1>c-j+1)continue;
40                 if((v&(1<<j-1))&&(v&(1<<j))&&c1<len) g[cur][v]=max(g[cur][v],f+(s[i][c1+1]==s[i][c1])+(s[i-1][c2]==s[i][c1+1]));
41                 else if(v&(1<<j-1)&&c1<len) g[cur][v|(1<<j)]=max(g[cur][v|(1<<j)],f+(s[i][c1+1]==s[i][c1]));
42                 else if(v&(1<<j)&&c1<len) g[cur][v]=max(g[cur][v],f+(s[i][c1+1]==s[i-1][c2]));
43                 else if(c1<len) g[cur][v|(1<<j)]=max(g[cur][v|(1<<j)],f);
44                 if(len-c1<=c-j)g[cur][(v|(1<<j))^(1<<j)]=max(g[cur][(v|(1<<j))^(1<<j)],f);
45             
46         
47     
48     for(int i=1;i<=g[cur].tot;i++)
49         if(count(g[cur].val[i],c)==strlen(s[r]+1))
50             ans=max(ans,g[cur].f[i]);
51     printf("%d\n",ans<<1);
52     return 0;
53 

 

以上是关于group 状压dp的主要内容,如果未能解决你的问题,请参考以下文章

POJ 3254 Corn Fields(状压DP)

动态规划---状压dp2

fzu2188 状压dp

状压DP(超详细!!!)

第一次接触状压DP

状压DP题集