【Day8】一名菜鸟ACMer的暑假训练
【Day8】一名菜鸟ACMer的暑假训练
- 上午补了昨晚AtCoder的题解(目前只做到E)
(博客+视频) - 下午在做一道别人问的题目,搞了好久。以及和佬探讨一道cf,目前是有了一个思路,但是由于我码力低下还没整出来
- 剩下的时间除了摸鱼,只做了几道kuangbin
(感觉最小生成树做起来顺了一些,也有可能是有了最短路的铺垫) - 打 Codeforces Round #805 (Div. 3)
AcWing 4291. 丛林之路
#include <bits/stdc++.h>
using namespace std;
const int N = 30, M = 80;
int n, k;
int fa[M];
struct Node {
int a, b, w;
bool operator<(const Node &t) const {
return w < t.w;
}
}e[M << 1];
void init () {
for (int i = 0; i <= n; i ++)
fa[i] = i;
}
int find (int x) {
if (x != fa[x])
fa[x] = find (fa[x]);
return fa[x];
}
int kruscal () {
//保证连通
init ();
sort (e, e + k);
int ans = 0;
for (int i = 0; i < k; i ++) {
int a = e[i].a, b = e[i].b, w = e[i].w;
a = find (a), b = find(b);
if (a != b) {
fa[a] = b;
ans += w;
}
}
return ans;
}
int main () {
while (cin >> n, n) {
k = 0, n --;
for (int i = 0; i < n; i ++) {
char id; cin >> id;
int a = id - 'A';
int m; cin >> m;
while (m --) {
int w;
cin >> id >> w;
int b = id - 'A';
e[k++] = {a, b, w}, e[k++] = {b, a, w};
}
}
cout << kruscal () << endl;
}
}
AcWing 4292. 网络连接
水水水
#include<bits/stdc++.h>
using namespace std;
const int N = 55, M = 1505;
int n, m, k;
int fa[N];
struct Node {
int a, b, w;
bool operator<(const Node &t) const {
return w < t.w;
}
}e[M << 1];
void init () {
for (int i = 1; i <= n; i ++)
fa[i] = i;
}
int find (int x) {
if (x != fa[x])
fa[x] = find (fa[x]);
return fa[x];
}
int kruscal () {
init ();
sort (e, e + k);
int ans = 0;
for (int i = 0; i < k; i ++) {
int a = e[i].a, b = e[i].b, w = e[i].w;
a = find (a), b = find (b);
if (a != b) {
fa[a] = b;
ans += w;
}
}
return ans;
}
int main () {
while (cin >> n, n) {
cin >> m;
k = 0;
while (m --) {
int a, b, w;
cin >> a >> b >> w;
// bool flag = true;
// for (int i = 0; i < k; i ++) {
// if (e[i].a == a && e[i].b == b && e[i].w < w) {
// flag = false;
// break;
// }
// }
// if (flag)
e[k ++] = {a, b, w}, e[k ++] = {b, a, w};
}
cout << kruscal () << endl;
}
}
//图中可能存在重边。
AcWing 4293. 建造空间站
抽象建图:
对于本来就已经相交或相切的圆,建一条权值为0的边;
对于相离的圆,边权为\(|O_1 O_2|-r_1-r_2\)
建完图之后,跑最小生成树即可
注意一些double的问题
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int n, k;
int fa[N];
struct zuobiao {
double x, y, z, r;
}a[N];
struct Node {
int a, b;
double w;
bool operator < (const Node &t) const {
return w < t.w;
}
}e[N*N*2];
void init () {
for (int i = 1; i <= N; i ++) //注意这里的更新是N
fa[i] = i;
}
int find (int x) {
if (x != fa[x])
fa[x] = find (fa[x]);
return fa[x];
}
double kruscal () {
init ();
sort (e, e + k);
double ans = 0;
for (int i = 0; i < k; i ++) {
int a = e[i].a, b = e[i].b;
double w = e[i].w; //分开来!!
a = find (a), b = find (b);
if (a != b) {
fa[a] = b;
ans += w;
}
}
return ans;
}
int main () {
int n;
while (cin >> n , n) {
k = 0;
for (int i = 1; i <= n; i ++) {
double x, y, z, r;
cin >> x >> y >> z >> r;
a[i] = {x, y, z, r};
}
for (int i = 1; i <= n; i ++)
for (int j = i + 1; j <= n; j ++) {
double x = a[i].x, y = a[i].y, z = a[i].z, r = a[i].r;
double xx = a[j].x, yy = a[j].y, zz = a[j].z, rr = a[j].r;
double d1 = (x-xx)*(x-xx) + (y-yy)*(y-yy) + (z-zz)*(z-zz), d2 = r + rr;
if (d1 <= d2*d2) e[k ++] = {i, j, 0}, e[k ++] = {j, i, 0};
else {
double w = sqrt (d1) - d2;
e[k ++] = {i, j, w}, e[k ++] = {j, i, w};
}
}
cout << fixed << setprecision(3) << kruscal () << endl;
}
}
//维系两个相离的球的通道长度为|AB|-r1-r2
//相交或相切就建一条为0的边
//然后跑最小生成树
AcWing 4294. 修建道路
和上一题真的蛮像的
就是已有的边权值为0,然后没连上的就加权值
#include <bits/stdc++.h>
using namespace std;
const int N = 105, M = N*N*2;
int n, m, k;
bool st[N][N]; //表示已有边
int dis[N][N], fa[N];
struct Node {
int a, b, w;
bool operator< (const Node &t) const {
return w < t.w;
}
}e[M];
void init () {
for (int i = 1; i <= N; i ++) fa[i] = i;
}
int find (int x) {
if (x != fa[x])
fa[x] = find (fa[x]);
return fa[x];
}
int kruscal () {
init ();
sort (e, e + k);
int ans = 0;
for (int i = 0; i < k; i ++) {
int a = e[i].a, b = e[i].b, w = e[i].w;
a = find (a), b = find (b);
if (a != b) {
fa[a] = b;
ans += w;
}
}
return ans;
}
int main () {
cin >> n;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++)
cin >> dis[i][j];
cin >> m;
while (m --) {
int a, b;
cin >> a >> b;
st[a][b] = st[b][a] = true;
}
for (int i = 1; i <= n; i ++)
for (int j = i + 1; j <= n; j ++) {
if (st[i][j] || st[j][i]) e[k++] = {i, j, 0}, e[k++] = {j, i, 0};
//需要自己建边
else e[k++] = {i, j, dis[i][j]}, e[k++] = {j, i, dis[j][i]};
}
cout << kruscal () << endl;
}
//每个都建边,如果是已有边,则权值为0
AcWing 4295. QS网络
TLE 了哭哭(明天改)
#include <bits/stdc++.h>
using namespace std;
const int N = 505, M = N*N*2;
int n, k;
int p[N], fa[N];
struct Node {
int a, b, w;
bool operator < (const Node &t) const {
return w < t.w;
}
}e[M];
void init () {
for (int i = 1; i <= n; i ++) fa[i] = i;
}
int find (int x) {
if (x != fa[x]) fa[x] = find (fa[x]);
return fa[x];
}
int kruscal () {
init ();
sort (e, e + k);
int ans = 0;
for (int i = 0; i < k; i ++) {
int a = e[i].a, b = e[i].b, w = e[i].w;
a = find (a), b =find (b);
if (a != b) {
fa[a] = b;
ans += w;
}
}
return ans;
}
void solve () {
k = 0;
cin >> n;
for (int i = 1; i <= n; i ++) cin >> p[i];
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++) {
int x; cin >> x;
int w = p[i] + p[j] + x;
e[k ++] = {i, j, w};
}
// for (int i = 1; i <= n; i ++)
// for (int j = i + 1; j <= n; j ++) {
// int w = p[i] + p[j] + dis[i][j];
// e[k ++] = {i, j, w}, e[k++] = {j, i, w};
// }
cout << kruscal () << endl;
}
int main () {
int t; cin >> t;
while (t --) solve ();
}
//不仅有边权还有点权
//直接在建边的时候顺便把点权加到边上
//love so sweet也太好听了!!!