SDUT 2021 summer team contest 1st(for 20)(补题)

Posted 佐鼬Jun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDUT 2021 summer team contest 1st(for 20)(补题)相关的知识,希望对你有一定的参考价值。

A - Amanda Lounges



题意: 有n个机场,m条路线(路线就是连接两个机场的边),对于每个机场可能需要等候室也可能不需要,如果输入2,代表路线连接的两个机场都需要建立,输入1,代表路线连接的其中一个机场建立(必须),输入0代表路线连接的两个机场都不可以建立,问你最少建立几个等候室
思路: 染色法+DFS
是否建立等候室看成是否染色,机场就是图论的点
对于输入2时,输入的两点颜色标记为’1’即可
对于输入1时,输入的两点颜色标记为‘-1’即可
对于上面两种情况,染色时如果出现矛盾情况,就直接“impossible”
对于输入1时,输入的两点暂时先标记为‘0’,代表颜色待定
并只对输入1时,输入的两点建边(为了方便下面dfs搜索)
然后此时建立完边后,一定会出现多个封闭的图,里面的点会有很多情况。
此时,将图进行分类,分为两类,分成图中点全是0,和图中有点不是0的
先对存在不是0点的图搜索一遍,因为建立的边都是因为输入1,而建立的,所以当知道其中一个点的颜色时,这个封闭图其他所有点的颜色都可以推导出来.例如:一个点是-1,那与这个点相连的点都应该是1,因为连接的点只能有1个等候室。一个点是1,那与这个点相连的点都应该是-1,原理如上。
在这个搜索+染色的过程中,如果发现某个点的颜色与相连的点颜色一致,那么说明矛盾,直接退出
再对全是0的图进行染色,此时就需要对这个图的某个点设置一个颜色,要么设置为1,要么设置为-1,对这两种情况都搜索一遍+染色,最终取染成1的最小值(实际不用代码搜索两遍,染色成0和染色成1最终形成的0和1的数量一定是相对的,知道一个就知道另一个情况的,所以直接取最小值即可)
(是个染色+DFS的好题,很考验代码能力)

#include <bits/stdc++.h>
using namespace std;
int n, m;
const int N = 4e5 + 10;
int e[N], ne[N], h[N], idx;
int color[N];
int vis[N];
int a, b, res;
void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; }
int dfs(int u, int c, int k) {
    if (k) {
        if (color[u] == 1) {
            b++;
        } else
            a++;
    } else {
        if (color[u] == 1) res++;
    }
    for (int i = h[u]; i != -1; i = ne[i]) {
        int j = e[i];
        if (color[j] == c) return 0;
        if (vis[j] == 0) {
            vis[j] = 1;
            if (color[j] == 0) {
                color[j] -= c;
            }
            if (!dfs(j, color[j], k)) {
                return 0;
            }
        }
    }
    return 1;
}
int main() {
    memset(h, -1, sizeof(h));
    cin >> n >> m;
    int flag = 1;
    //012分类染色建边
    for (int i = 0; i < m; i++) {
        int x, y, z;
        scanf("%d%d%d", &x, &y, &z);
        if (z == 2) {
            if (color[x] == -1 || color[y] == -1) {
                flag = 0;
            }
            color[x] = 1, color[y] = 1;
        } else if (z == 0) {
            if (color[x] == 1 || color[y] == 1) {
                flag = 0;
            }
            color[x] = -1, color[y] = -1;
        } else {
            add(x, y), add(y, x);
        }
    }
    //对有1或-1点的图,进行扩散染色
    for (int i = 1; i <= n; i++) {
        if (!vis[i] && color[i]) {
            vis[i] = 1;
            if (dfs(i, color[i], 0) == 0) {
                flag = 0;
            }
        }
    }
    //对于只有0的图,选一个点设置为1,再扩散染色
    for (int i = 1; i <= n; i++) {
        if (vis[i] == 1) {
            continue;
        }
        a = 0, b = 0, vis[i] = 1, color[i] = 1;
        if (dfs(i, 1, 1) == 0) {
            flag = 0;
        }
        res += min(a, b);
    }
    if (flag)
        printf("%d\\n", res);
    else
        puts("impossible");
    return 0;
}

E - Opening Ceremony


题意: n个高楼,有两种操作,要么使选择一个数,高度低于这个数的高楼不管,高度高于这个数的所有高楼都减低一层。要么直接摧毁一个高楼,问最少多少次操作使所有高楼都被摧毁
思路: 一开始想的是一层一层砍楼层,看横着砍一次,然后算需要再竖着砍掉几个高楼,直到砍完了为止,最后所有情况取最小值即可,然后发现横着砍的时候,最小倒的楼肯定是最矮的,其次是次矮的,依次下去。然后这样就可以决策了,从前往后,选择一个楼,矮于这个楼的统统横着砍掉(横砍次数就是选择的楼的高度)+后面要竖着砍的高楼个数,最后统统算一遍取最小值。

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;

int a[N];
int main() {
    int n;
    cin >> n;
    int res = n;
    for (int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
    }
    sort(a, a + n);
    res = min({n, a[n - 1]});
    for (int i = 1; i <= n; i++) {
        res = min(res, n - i + a[i - 1]);
    }
    cout << res << endl;
}

To be continued
如果你有任何建议或者批评和补充,请留言指出,不胜感激

以上是关于SDUT 2021 summer team contest 1st(for 20)(补题)的主要内容,如果未能解决你的问题,请参考以下文章

2021-08-03SDUT 2021 Summer Individual Contest - 4(for 20)(补题)

SDUT 2021 Summer Individual Contest - 7(补题)

SDUT 2021 Autumn Team Contest 10th(补题)

SDUT 2021 Autumn Team Contest 9th(补题)

SDUT 2022 Winter Team Contest - 1

SDUT 2022 Winter Team Contest - 1