状压DP小拼盘

有的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 }
hdu 6149 Valley Numer II
扫描二维码关注公众号,回复: 2796892 查看本文章

猜你喜欢

转载自www.cnblogs.com/eternhope/p/9487868.html