AtCoder Beginner Contest 142 E.Get Everything

E.Get Everything

Description:

有n个宝箱,给定m个钥匙的价钱和它能开的宝箱,求开完所有宝箱要的最少钥匙数量

Solution:

直接想到的是网络流,但是当时手敲敲错了。。。疯狂出bug。。就该copy模板
然后队友是DLX过的(nb!!)
这题还可以状压dp

AC Code(dp):

//https://atcoder.jp/contests/abc142/tasks/abc142_e
#include <iostream>
#include <vector>
#include <cstring>

using namespace std;
constexpr int maxn = 1 << 13;
int n, m;
int dp[maxn];
bool vis[maxn];
vector<int> availableSets;

void init() { memset(dp, 0x3f, sizeof(dp)); }

void input() {
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        int price, foo, lockSet{};
        cin >> price >> foo;
        for (int j = 0; j < foo; ++j) {
            int bit;
            cin >> bit;
            lockSet |= (1 << (bit - 1));
        }
        dp[lockSet] = min(dp[lockSet], price);
        if (!vis[lockSet])
            availableSets.push_back(lockSet);
        vis[lockSet] = true;
    }
}

int solve() {
    int tot = 1 << n;
    for (auto currSet:availableSets)
        for (int nextSet = 0; nextSet < tot; ++nextSet)
            dp[currSet | nextSet] = min(dp[currSet | nextSet], dp[currSet] + dp[nextSet]);
    int res = dp[(1 << n) - 1];
    return res < 0x3f3f3f3f ? res : -1;
}

int main() {
    freopen("/home/ngkimbing/Disk_F/CLionProjects/acm/in.txt", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    init();
    input();
    cout << solve();
    return 0;
}

AC Code(DLX) :

Author: Zhe Wang

//https://atcoder.jp/contests/abc142/tasks/abc142_e
//Author: Zhe Wang
#include<iostream>
#include<sstream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<string>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<map>
#include<set>

#define mem(a, b) memset(a,b,sizeof(a))
#define random(a, b) (rand()%(b-a+1)+a)
#define ll long long
#define ull unsigned long long
#define e 2.71828182
#define Pi acos(-1.0)
#define ls(rt) (rt<<1)
#define rs(rt) (rt<<1|1)
#define lowbit(x) (x&(-x))
using namespace std;
const int MAXN = 1e3 + 5;
const int MAXM = 20;
const int MAX = 2e4 + 5;
const int INF = 0x7fffffff;
int a[MAXN], b[MAXN];
int c[MAXM];

struct DLX {
    int n, m, cnt, g, tmp;
    int U[MAX], D[MAX], R[MAX], L[MAX], row[MAX], col[MAX];
    int H[MAXN], S[MAXM];
    bool v[MAX];

    void init(int _n, int _m) {
        n = _n, m = _m, g = INF, tmp = 0;
        for (int i = 0; i <= m; ++i)
            S[i] = 0, U[i] = D[i] = i, L[i] = i - 1, R[i] = i + 1;
        R[m] = 0, L[0] = m, cnt = m;
        mem(H, -1);
    }

    void add(int r, int c) {
        ++S[col[++cnt] = c];
        row[cnt] = r;
        D[cnt] = D[c], U[D[c]] = cnt;
        U[cnt] = c, D[c] = cnt;
        if (H[r] < 0) H[r] = L[cnt] = R[cnt] = cnt;
        else R[cnt] = R[H[r]], L[R[H[r]]] = cnt, L[cnt] = H[r], R[H[r]] = cnt;
    }

    void remove(int c) {
        for (int i = D[c]; i != c; i = D[i])
            L[R[i]] = L[i], R[L[i]] = R[i];
    }

    void resume(int c) {
        for (int i = U[c]; i != c; i = U[i])
            L[R[i]] = R[L[i]] = i;
    }

    int h() {
        int ret = 0;
        for (int i = R[0]; i != 0; i = R[i]) v[i] = true;
        for (int i = R[0]; i != 0; i = R[i]) {
            if (!v[i]) continue;
            //ret++,v[i]=false;
            v[i] = false;
            int tt = INF;
            for (int j = D[i]; j != i; j = D[j]) {
                tt = min(tt, a[row[j]]);
                for (int k = R[j]; k != j; k = R[k])
                    v[col[k]] = false;
            }
            ret += tt;
        }
        return ret;
    }

    void dance(int d) {
        if (tmp + h() >= g) return;
        //if(tmp>=g) return;
        if (R[0] == 0) {
            if (tmp < g) g = tmp;
            return;
        }
        int c = R[0];
        for (int i = R[0]; i != 0; i = R[i])
            if (S[i] < S[c]) c = i;
        for (int i = D[c]; i != c; i = D[i]) {
            remove(i);
            for (int j = R[i]; j != i; j = R[j]) remove(j);
            tmp += a[row[i]];//cout<<"a:"<<a[row[i]]<<endl;
            dance(d + 1);
            tmp -= a[row[i]];
            for (int j = L[i]; j != i; j = L[j]) resume(j);
            resume(i);
        }
        return;
    }
} dlx;

int read() {
    int s = 1, x = 0;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') s = -1;
        ch = getchar();
    }
    while (isdigit(ch)) {
        x = 10 * x + ch - '0';
        ch = getchar();
    }
    return x * s;
}

int main() {
    int N = read(), M = read();
    dlx.init(M, N);
    for (int i = 1; i <= M; ++i) {
        a[i] = read(), b[i] = read();
        for (int j = 1; j <= b[i]; ++j) {
            c[j] = read();
            dlx.add(i, c[j]);
        }
    }
    dlx.dance(0);
    if (dlx.g == INF) cout << -1;
    else cout << dlx.g;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值