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(补题)