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;
}