题意:
给你N个点,有k个为高点,其他为低点,现在这N个点有m条边,问你最多能组成多少个两个高点一个低点,低点和两个高点都有边相连这样的状态。
每个点只能出现在一个状态里面。
题解:
考虑将高点进行状态压缩一下。那么枚举每一个低点,看看能对那些状态有影响,那么就更新那些状态,相当于外层是个01背包,枚举物品,内层就是一个状压dp。
1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=(a);i<=(b);++i) 4 using namespace std; 5 6 const int N=33; 7 int T,n,m,K,x,y,now,dp[2][1<<15],h[N],mp[33][33],a[N]; 8 9 void gmax(int &a,int b){if(a<b)a=b;} 10 11 int main(){ 12 scanf("%d",&T); 13 while(T--) 14 { 15 scanf("%d%d%d",&n,&m,&K); 16 mst(dp,0),mst(h,0),mst(mp,0); 17 F(i,1,m) 18 { 19 scanf("%d%d",&x,&y); 20 mp[x][y]=mp[y][x]=1; 21 } 22 F(i,0,K-1)scanf("%d",a+i),h[a[i]]=1; 23 int U=(1<<K)-1; 24 now=0; 25 F(i,1,n) 26 { 27 if(h[i])continue; 28 now^=1; 29 memcpy(dp[now],dp[now^1],sizeof(dp[now])); 30 F(j,0,U)F(k,0,K-1) 31 { 32 if((j&(1<<k))||!mp[i][a[k]])continue; 33 F(t,k+1,K-1) 34 { 35 if((j&(1<<t))||!mp[i][a[t]])continue; 36 gmax(dp[now][j|(1<<k)|(1<<t)],dp[now^1][j]+1); 37 } 38 } 39 } 40 int ans=0; 41 F(i,0,U)gmax(ans,dp[now][i]); 42 printf("%d ",ans); 43 } 44 return 0; 45 }