HDU 6149 状压dp

题意:

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


思路:

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


代码:

#include <bits/stdc++.h>
using namespace std;

bool g[50][50], vis[50];
int dp[50][(1 << 15) + 10], high[20], low[50];
vector <pair <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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值