hdu-6149 Valley Numer II 状压DP
http://acm.hdu.edu.cn/showproblem.php?pid=6149
把点分为low和high点,high点最多只有15个,所以可以用压位来处理其选取状态。
枚举low点,然后暴力枚举low点能连接的high点,记忆化搜索一下就好了
#include <iostream> #include <string> #include <queue> #include <vector> #include <cstring> using namespace std; const int N=35; int n,m,k; vector<int> g[N]; int bit[30]; bool h[N]; int has[N]; vector<int> low; vector<int> hig; int ans; int dp[N][40000]; void dfs(int id,int d,int a) { if(id==low.size()) { ans=max(ans,a); return; } if(a<=dp[id][d])return; dp[id][d]=a; int li=low[id]; for(int i=0; i<g[li].size(); i++) { int pi=g[li][i]; if(!h[pi])continue; int hid1=has[pi]; if(bit[hid1]&d)continue; for(int j=i+1; j<g[li].size(); j++) { int pj=g[li][j]; if(!h[pj])continue; int hid2=has[pj]; if(bit[hid2]&d)continue; dfs(id+1,d+bit[hid1]+bit[hid2],a+1); } } dfs(id+1,d,a); } int main() { cin.sync_with_stdio(false); int t; bit[0]=1; for(int i=1; i<=15; i++) bit[i]=bit[i-1]*2; //cout<<bit[15]<<endl;32768 cin>>t; while(t--) { cin>>n>>m>>k; for(int i=0;i<n-k;i++) for(int j=0;j<(1<<k);j++) dp[i][j]=-1; for(int i=1; i<=n; i++) g[i].clear(); low.clear(); hig.clear(); ans=0; fill(h,h+N,false); for(int i=0; i<m; i++) { int a,b; cin>>a>>b; g[a].push_back(b); g[b].push_back(a); } for(int i=0; i<k; i++) { int a; cin>>a; h[a]=true; } for(int i=1; i<=n; i++) { if(!h[i]) has[i]=low.size(),low.push_back(i); else has[i]=hig.size(),hig.push_back(i); } for(int i=0;i<low.size();i++) { int lid=low[i]; for(int j=g[lid].size()-1;j>=0;j--) { if(!h[g[lid][j]]) g[lid].erase(g[lid].begin()+j); } } dfs(0,0,0); cout<<ans<<endl; } return 0; }