AtCoder Beginner Contest 142(补题)

Posted 佐鼬Jun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder Beginner Contest 142(补题)相关的知识,希望对你有一定的参考价值。

E - Get Everything

链接: link.

题意:

N N N把需要解锁的宝箱,编号为 1 − N 1-N 1N,现在有 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(bitnow)=min(dp(bitnow),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 234

AtCoder Beginner Contest 115 题解

AtCoder Beginner Contest 154 题解

AtCoder Beginner Contest 103

AtCoder Beginner Contest 228

AtCoder Beginner Contest 242