有的DP题,某一部分的状态只有两种,选或不选。
开数组记录,代价太大,转移不方便。
状态压缩意为,用 “0/1“ 表示 “选/不选“ 。
把状态表示为二进制整数。
There are 10 kinds of people in the world, who knows binary and who doesn't.
用位运算判断条件并转移状态。
hdu 6149 Valley Numer II
用f[i][j]表示选到前i个点,状态为j的答案。
枚举其他两个高点。
转移之前判断之前是否用过,以及高低点之间是否有连边。
所以用邻接矩阵表示连边比较方便。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int t; 7 int n,m,k; 8 int c[35][35]; 9 int h[35]; 10 int v[35]; 11 int f[35][(1<<16)+1]; 12 int ans; 13 14 int main() 15 { 16 scanf("%d",&t); 17 while(t--) 18 { 19 memset(f,0,sizeof(f)); 20 memset(c,0,sizeof(c)); 21 memset(h,0,sizeof(h)); 22 memset(v,0,sizeof(v)); 23 scanf("%d%d%d",&n,&m,&k); 24 for(int i=1;i<=m;i++) 25 { 26 int q,w; 27 scanf("%d%d",&q,&w); 28 c[q][w]=1; 29 c[w][q]=1; 30 } 31 for(int i=0;i<k;i++) 32 { 33 scanf("%d",&h[i]); 34 v[h[i]]=1; 35 } 36 int st=(1<<k); 37 ans=0; 38 for(int i=1;i<=n;i++) 39 { 40 for(int j=0;j<st;j++)f[i][j]=f[i-1][j]; 41 if(v[i])continue; 42 for(int j=0;j<st;j++) 43 { 44 for(int q1=0;q1<k;q1++) 45 { 46 if(j&(1<<q1))continue; 47 if(!c[i][h[q1]])continue; 48 for(int q2=0;q2<q1;q2++) 49 { 50 if(j&(1<<q2))continue; 51 if(!c[i][h[q2]])continue; 52 f[i][(j|(1<<q1))|(1<<q2)]=max(f[i][(j|(1<<q1))|(1<<q2)],f[i-1][j]+1); 53 } 54 } 55 } 56 } 57 for(int j=0;j<st;j++)ans=max(ans,f[n][j]); 58 printf("%d\n",ans); 59 } 60 return 0; 61 }
扫描二维码关注公众号,回复:
2796892 查看本文章