AtCoder Beginner Contest 142(补题)
Posted 佐鼬Jun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder Beginner Contest 142(补题)相关的知识,希望对你有一定的参考价值。
E - Get Everything
链接: link.
题意:
有 N N N把需要解锁的宝箱,编号为 1 − N 1-N 1−N,现在有 M M M把钥匙,每把钥匙价值 a i a_i ai元,每把钥匙可以解锁 b i b_i bi个宝箱,可以解锁的宝箱种类分别为 c i 1 , c i 2 . . . . c i b i c_{i1},c_{i2}....c_{ibi} ci1,ci2....cibi。问你花最少多少钱可以把所有钥匙都解锁
思路:
宝箱的数量较小,可以用2进制状态压缩来表示每个宝箱持有的状态。例如1号宝箱就是
00000001
00000001
00000001,2号就是00000010…依次往后。
现在假设你当前钥匙能开的宝箱的二进制是
n
o
w
now
now,当前的钥匙为
i
i
i号钥匙
定义
d
p
(
b
i
t
)
dp(bit)
dp(bit)为该二进制下解开这些宝箱所需要的最少钱数
那么此时
d
p
(
b
i
t
∣
n
o
w
)
=
m
i
n
(
d
p
(
b
i
t
∣
n
o
w
)
,
d
p
(
b
i
t
)
+
a
[
i
]
)
dp(bit|now)=min(dp(bit|now),dp(bit)+a[i])
dp(bit∣now)=min(dp(bit∣now),dp(bit)+a[i]),初始状态
d
p
(
0
)
=
0
dp(0)=0
dp(0)=0其他的状态初始化为
i
n
f
inf
inf,最终答案就是
d
p
(
(
1
<
<
N
)
−
1
)
dp((1<<N)-1)
dp((1<<N)−1)的值
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
int n, m;
int a[1111], b[1111];
int c[1111][20];
vector<int> dp(5050, inf);
int main() {
cin >> n >> m;
for (int i = 1; i <= m; i++) {
cin >> a[i] >> b[i];
for (int j = 1; j <= b[i]; j++) {
cin >> c[i][j];
}
}
dp[0] = 0;
for (int i = 1; i <= m; i++) {
int now = 0;
for (int j = 1; j <= b[i]; j++) {
now |= (1 << (c[i][j] - 1));
}
for (int bit = 0; bit < (1 << n); bit++) {
dp[bit | now] = min(dp[bit | now], dp[bit] + a[i]);
}
}
if (dp[(1 << n) - 1] == inf) {
puts("-1");
} else {
cout << dp[(1 << n) - 1] << endl;
}
return 0;
}
F - Pure
链接: link.
题意:
给定一张 N N N个点和 M M M 条边的有向连通图,保证没有重边和自环。现在要找出一个子图,使得子图内每个点的入度和出度都恰好是 1 1 1。输出这个子图。
思路:
子图的每个点的入度和出度都恰好是1,那就说明要找一个环,且这个环中的每个点都是出去一条边,也进来一条边,那么此时只需要找图中的最小环即可,如果不是最小环,可能内部有些点的出度或者入读不是恰好为1,而是 > 1 >1 >1,只有最小环一定是出度入读恰好为1,这个可以用反证法简单证明。找最小环,直接用dfs来跑即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 2222, M = N * 2;
int h[N], e[M], ne[M], idx;
int d[N];
int minv = 0x3f3f3f3f;
int ans[N];
int temp[N];
int n, m;
void add_edge(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; }
void dfs(int u, int root, int dis) {
temp[dis] = u;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (j == root) {
if (minv > d[u] - d[root] + 1) {
minv = d[u] - d[root] + 1;
int id = 0;
for (int k = d[root]; k <= dis; k++) {
ans[id++] = temp[k];
}
}
} else if (!d[j]) {
d[j] = d[u] + 1;
dfs(j, root, dis + 1);
}
}
}
int main() {
cin >> n >> m;
memset(h, -1, sizeof(h));
while (m--) {
int a, b;
cin >> a >> b;
add_edge(a, b);
}
for (int i = 1; i <= n; i++) {
memset(d, 0, sizeof(d));
d[i] = 1;
dfs(i, i, 1);
}
if (minv == 0x3f3f3f3f)
puts("-1");
else {
cout << minv << endl;
for (int i = 0; i < minv; i++) {
cout << ans[i] << endl;
}
}
}
To be continued
如果你有任何建议或者批评和补充,请留言指出,不胜感激
以上是关于AtCoder Beginner Contest 142(补题)的主要内容,如果未能解决你的问题,请参考以下文章
AtCoder Beginner Contest 115 题解