2019牛客国庆集训派对day3 G排列(状压dp)

题目传送门

一道很好的状压DP,状态是当前的占位情况,排序操作和第21次CSP认证的第四题作用类似。

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1 << 22;
const ll inf = 1e15;

int n, m, x, y;
int num[N], p[22];
ll dp[N];
vector<int> vt[22];

int main(){
    for(int i = 1; i < N; ++i)  num[i] = num[i - (i & -i)] + 1;
    while(scanf("%d%d", &n, &m) != EOF){
        for(int i = 0; i < n; ++i)  scanf("%d", &p[i]), vt[i].clear();
        for(int i = 0; i < (1 << n); ++i)  dp[i] = inf;
        while(m--){
            scanf("%d%d", &x, &y);
            vt[x - 1].emplace_back(y - 1);
            vt[y - 1].emplace_back(x - 1);
        } 
        dp[0] = 0;
        // 按照从小到大的顺序插值,满足绝对值的条件
        sort(p, p + n);
        // dp[i]代表i表示的位置填充状态的最小值
        for(int i = 0; i < (1 << n); ++i){
            for(int t = 0; t < n; ++t) if(!(i >> t & 1)){
                int cnt = 0;
                for(auto &x : vt[t]){
                    if(i >> x & 1)  ++cnt;	// 若第x个座位已经被包含,该座位上的值一定小于当前要插的值 
                    else  --cnt;
                }
                dp[i | (1 << t)] = min(dp[i | (1 << t)], dp[i] + 1LL * p[num[i]] * cnt);
            }
        }
        printf("%lld
", dp[(1 << n) - 1]);
    }
    return 0;
}
你只有十分努力,才能看上去毫不费力。
原文地址:https://www.cnblogs.com/214txdy/p/14151852.html