/** 题目:hdu6149 Valley Numer II 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6149 题意: 众所周知,度度熊非常喜欢图。 为了形成山谷,首先要将一个图的顶点标记为高点或者低点。 标记完成后如果一个顶点三元组<X, Y, Z>中, X和Y之间有边,Y与Z之间也有边,同时X和Z是高点,Y是低点,那么它们就构成一个valley。 度度熊想知道一个无向图中最多可以构成多少个valley,一个顶点最多只能出现在一个valley中。 ● 1≤T≤20 ● 1≤N≤30 ● 1≤M≤N*(N-1)/2 ● 0≤K≤min(N,15) ● 1≤Xi, Yi≤N, Xi!=Yi ● 1≤Vi≤N 思路:由于k最大是15,所以可以分组背包+状态压缩 因为每两个高点和一个低点才能构成一个三元组,k最大15,所以最多7个三元组; 所有的低点作为分组条件。 每一组存入可以和该低点构成三元组的pair<x,z>,用s表示状态; dp[i][s]表示放入i体积,高点状态为s可以获得的最多三元组; dp[i][s] = max(dp[i][s],dp[i-1][s-s1]+1) (s&(s1)==0) ps:自己老是在这个地方搞错,dp[7][i]这里的第一维要开到8以上!!! */ #include <cstdio> #include <cstring> #include <algorithm> #include <set> #include <iostream> #include <cmath> #include <vector> #include <map> using namespace std; typedef long long LL; #define ms(x,y) memset(x,y,sizeof x) typedef pair<int, int> P; const int inf = 0x3f3f3f3f; const int mod = 1e9 + 7; const int N =10005; int dp[8][1<<15]; vector<int> v[31]; int f[33][33]; int gao[33], pos[33]; vector<int> g; int main() { int T; int n, m, k; cin>>T; while(T--) { scanf("%d%d%d",&n,&m,&k); ms(f,0); int x, y; for(int i = 1; i <= m; i++){ scanf("%d%d",&x,&y); f[x][y] = 1; f[y][x] = 1; } ms(gao,0); g.clear(); for(int i = 1; i <= k; i++){ scanf("%d",&x); pos[x] = i-1; g.push_back(x); gao[x] = 1; } for(int i = 1; i<= n; i++) v[i].clear(); for(int i = 1; i <= n; i++){ if(gao[i]==0){ for(int j = 0; j<g.size();j++){ for(int z = j+1; z <g.size(); z++){ if(f[i][g[j]]&&f[i][g[z]]){ v[i].push_back((1<<pos[g[j]])|(1<<pos[g[z]])); } } } } } memset(dp, -inf, sizeof dp); dp[0][0] = 0; int len = 1<<k; for(int i = 1; i <= n; i++){ if(gao[i]||(int)v[i].size()==0) continue; for(int j = 7; j >= 1; j--){ for(int x = 0; x < v[i].size(); x++){ for(int y = 0; y < len; y++){ if((y&v[i][x])==v[i][x]){ dp[j][y] = max(dp[j][y],dp[j-1][y-v[i][x]]+1); } } } } } int mas = 0; for(int i = 1; i <= 7; i++){ for(int j = 0; j < len; j++){ mas = max(mas,dp[i][j]); } } printf("%d ",mas); } return 0; }