hdu6149 Valley Numer II 分组背包+状态压缩

/**
题目: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;
}
原文地址:https://www.cnblogs.com/xiaochaoqun/p/7390995.html