牛客算法周周练13

    技术2022-07-11  75

    A、最小生成树

    小 A 有一张 n 个点的带权无向图,这张无向图非常特别,首先第 i 个点有一个点权 ai,之后这张无向图是一张完全图,且边 (u,v) 的权值为 au+av 现在小 A 想找一个这张图的边权之和最小的生成树,需要你来帮帮他

    题解: 每个点都和最小那个点连接形成的树即最小生成树 注意:使用长整形

    AC代码:

    #include<iostream> #include<algorithm> using namespace std; #define ll long long const int maxn = 1e5 + 15; ll a[maxn]; int main() { int n; cin >> n; for (int i = 0; i < n; i++) cin >> a[i]; sort(a, a + n); ll ans = 0; for (int i = 1; i < n; i++) ans += a[0] + a[i]; cout << ans << endl; return 0; }

    B、病毒感染 有一天clccle和rqy走在某个国家的街头上,机智的rqy却发现周围的行人不太对劲,他们嘴里念念有词,说着"sqn tql!",一边漫无目的的行走,clccle也发现了这一点,却惊讶的发觉这种奇怪的病毒会向周围的城市,最终会感染整个国家,因为网络已经崩溃,所以她们忘记了自己所在的城市,她们唯一知道的是这种病毒是从当前她们所在的城市开始传播的,并且这个国家的所有城市到这个城市的距离和最小(所有道路的距离都为1),现在给定聪明的你一张整个国家的地图,请你帮rqy和clccle找到她们现在可能在这个国家的哪一个城市.

    题解: 树的重心板子题

    AC代码:

    #include<iostream> #include<algorithm> #include<stdio.h> #include<vector> using namespace std; #define ll long long #define inf 0x3f3f3f3f const int maxn = 1e5 + 15; vector<int>G[maxn]; vector<int>ans[maxn]; int minn; int d[maxn]; int n, m; /* 树的重心求法:遍历所有点的子树的大小,然后重心存在的那个点就是最大子树最小的那个点 */ void dfs(int u, int fa) { d[u] = 1; int maxx = 0; for (int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if (v != fa) { dfs(v, u); d[u] += d[v]; maxx = max(maxx, d[v]); } } maxx = max(maxx, n - d[u]); if (maxx <= minn) { minn = maxx; ans[minn].push_back(u); } } int main() { cin >> n >> m; for (int i = 0; i < m; i++) { int x, y; cin >> x >> y; G[x].push_back(y); G[y].push_back(x); } minn = inf; dfs(1, 0); sort(ans[minn].begin(), ans[minn].end()); for (int i = 0; i < ans[minn].size(); i++) cout << ans[minn][i] << " "; return 0; }

    C、Shooping 你要买n件物品,其中有一些是凳子。 商场正在举行促销活动,如果购物车中有至少一个凳子,那么你可以半价购买这个购物车中最贵的一个物品。 你有m辆购物车,请最小化你的花费。

    题解: 找出min(m,凳子数量),然后对前k大的物品进行打折就好

    AC代码:

    #include<iostream> #include<algorithm> #include<stdio.h> using namespace std; #define ll long long const int maxn = 1e3 + 15; bool cmp(double a, double b) { return a > b; } int main() { int t; cin >> t; while (t--) { double a[maxn]; int num = 0; int n, m; cin >> n >> m; int x; double ans = 0; for (int i = 0; i < n; i++) { cin >> a[i] >> x; ans += a[i]; if (x == 1) num++; } sort(a, a + n, cmp); for (int i = 0; i < min(num, m); i++) ans -= a[i] / 2; printf("%.1lf\n", ans); } return 0; }

    D、铺地毯 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯。一共有n张地毯,编号从1到n。现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上。地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的编号。注意:在矩形地毯边界和四个顶点上的点也算被地毯覆盖。

    题解: 将所有地毯按顺序依次铺上,然后倒序查找最上面的即可

    AC代码:

    #include<iostream> #include<algorithm> using namespace std; #define ll long long const int maxn = 1e6 + 15; struct node { int a, b, g, k; }a[maxn]; int main() { int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i].a >> a[i].b >> a[i].g >> a[i].k; int x, y; cin >> x >> y; int is_ok = 0; for (int i = n; i >= 1; i--) { if (a[i].a > x || a[i].b > y) continue; else if (x <= a[i].a + a[i].g && x >= a[i].a && y >= a[i].b && y <= a[i].b + a[i].k) { cout << i << endl; is_ok = 1; break; } } if (is_ok == 0) cout << -1 << endl; return 0; }

    E、金币陷阱 最近,奶牛们热衷于把金币包在面粉里,然后把它们烤成馅饼。第i块馅饼中含有Ni(1<=Ni<=25)块金币,并且,这个数字被醒目地标记在馅饼表面。 奶牛们把所有烤好的馅饼在草地上排成了一个R行(1<=R<=100)C列(1<=C<=100)的矩阵。你现在站在坐标为(1,1)的馅饼边上,当然,你可以拿到那块馅饼里的所有金币。你必须从现在的位置,走到草地的另一边,在坐标为(R,C)的馅饼旁边停止走动。每做一次移动,你必须走到下一列的某块馅饼旁边,并且,行数的变动不能超过1(也就是说,如果现在你站在坐标为(r,c)的馅饼边上,下一步你可以走到坐标为(r-1,c+1),(r,c+1),或者(r+1,c+1)的馅饼旁边)。当你从一块馅饼边经过,你就可以拿走馅饼里所有的金币。当然啦,你一定不会愿意因半路离开草地而失去唾手可得的金币,但,最终你一定得停在坐标为(R,C)的馅饼旁边。 现在,你拿到了一张标记着馅饼矩阵中,每一块馅饼含金币数量的表格。那么,按照规则,你最多可以拿到多少金币呢?

    题解: 大佬们拿dp写的,卑微的我看不懂,只好裸dfs了

    搜索代码:

    #include<iostream> #include<algorithm> using namespace std; #define ll long long const int N = 1e2 + 5; #define inf 0x3f3f3f3f int a[N][N]; int vis[N][N]; int R, C; int dir[3][2] = { {0, 1}, {-1, 1}, {1, 1} }; int dfs(int x, int y) { if (x == R && y == C) return 0; if (vis[x][y]) return vis[x][y]; vis[x][y] = -inf; for (int i = 0; i < 3; i++) { int xx = x + dir[i][0]; int yy = y + dir[i][1]; if (xx >= 1 && xx <= R && yy >= 1 && yy <= C) vis[x][y] = max(vis[x][y], dfs(xx, yy) + a[xx][yy]); } return vis[x][y]; } int main() { cin >> R >> C; for (int i = 1; i <= R; i++) for (int j = 1; j <= C; j++) cin >> a[i][j]; int ans = dfs(1, 1) + a[1][1]; cout << ans << endl; return 0; }

    dp代码:

    #include<iostream> #include<algorithm> #include<string.h> using namespace std; #define ll long long const int N = 1e2 + 5; #define inf 0x3f3f3f3f int a[N][N], dp[N][N]; int R, C; int main() { cin >> R >> C; for (int i = 1; i <= R; i++) for (int j = 1; j <= C; j++) cin >> a[i][j]; dp[1][1] = a[1][1]; for (int i = 2; i <= C; i++) { for (int j = 1; j <= R; j++) { if (dp[j][i - 1] != 0) dp[j][i] = max(dp[j][i], dp[j][i - 1] + a[j][i]); if (dp[j + 1][i - 1] != 0) dp[j][i] = max(dp[j][i], dp[j + 1][i - 1] + a[j][i]); if (dp[j - 1][i - 1] != 0) { dp[j][i] = max(dp[j][i], dp[j - 1][i - 1] + a[j][i]); } } } cout << dp[R][C] << endl; return 0; }
    Processed: 0.020, SQL: 9