HDU 6149 状压dp

题意:

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6149
中文题。


思路:

状态压缩,将高点的选择情况压位。dp[i][S]表示的是枚举到第i个低点,且当前选择高点状态为S的最大山谷数。转移简单,注意细节。


代码:

#include 
using namespace std;

bool g[50][50], vis[50];
int dp[50][(1 << 15) + 10], high[20], low[50];
vector int, int> > vec[30];

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int n, m, k;
        scanf("%d%d%d", &n, &m, &k);
        memset(g, 0, sizeof g);
        for (int i = 1; i <= m; ++i) {
            int u, v;
            scanf("%d%d", &u, &v);
            g[u][v] = g[v][u] = 1;
        }
        memset(vis, 0, sizeof vis);
        for (int i = 0; i < k; ++i) {
            scanf("%d", &high[i]);
            vis[high[i]] = 1;
        }
        int cnt = 0;
        for (int i = 1; i <= n; ++i) {
            if (!vis[i]) low[cnt++] = i;
        }
        for (int i = 0; i < cnt; ++i) {
            vec[i].clear();
            for (int j = 0; j < k; ++j) {
                if (low[i] == high[j] || !g[low[i]][high[j]]) continue;
                for (int t = j + 1; t < k; ++t) {
                    if (low[i] == high[t] || !g[low[i]][high[t]]) continue;
                    vec[i].push_back(make_pair(j, t));
                }
            }
        }
        memset(dp, 0, sizeof dp);
        dp[0][0] = 0;
        for (int i = 0; i < cnt; ++i) {
            for (int S = 0; S < (1 << k); ++S) {
                dp[i + 1][S] = max(dp[i + 1][S], dp[i][S]);
                for (int j = 0, sz = vec[i].size(); j < sz; ++j) {
                    int u = vec[i][j].first, v = vec[i][j].second;
                    if ((S & (1 << u)) || (S & (1 << v))) continue;
                    dp[i + 1][S | (1 << u) | (1 << v)] = max(dp[i + 1][S | (1 << u) | (1 << v)], dp[i][S] + 1);
                }
            }
        }
        int ans = 0;
        for (int S = 0; S < (1 << k); ++S)
            ans = max(ans, dp[cnt][S]);
        printf("%d\n", ans);
    }
    return 0;
}

你可能感兴趣的:(状压dp)