A - 氪金带东
题意
实验室里原先有一台电脑(编号为1),最近氪金带师咕咕东又为实验室购置了N-1台电脑,编号为2到N。每台电脑都用网线连接到一台先前安装的电脑上。但是咕咕东担心网速太慢,他希望知道第i台电脑到其他电脑的最大网线长度,但是可怜的咕咕东在不久前刚刚遭受了宇宙射线的降智打击,请你帮帮他。
提示: 样例输入对应这个图,从这个图中你可以看出,距离1号电脑最远的电脑是4号电脑,他们之间的距离是3。 4号电脑与5号电脑都是距离2号电脑最远的点,故其答案是2。5号电脑距离3号电脑最远,故对于3号电脑来说它的答案是3。同样的我们可以计算出4号电脑和5号电脑的答案是4.
解题思路
- 本题电脑之间的连接是一个树的结构,而本题需要求取树上任意一点到其他点的最长距离。而树恰好有一条性质适合本题使用:距离任意点最远的点一定是直径的一个端点。
- 那么我们可以先找到树的直径的两个端点,再计算树上任意一点到两端点的距离,即可获得答案。
- 求取树的直径两端点,可以先从树上任意一点开始遍历,找到距离最远的点即为直径的一个端点,再从这个点遍历,最远的即为直径的另一个端点。
代码
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
struct edge{
int u,w;
};
vector<edge> graph[10005];
int p1[10005],p2[10005];
bool r[10005];
int v,vs;
void dfs1(int i, int s, int* p){
bool k = 0;
r[i] = true;
if(p!=nullptr)
p[i] = s;
for(unsigned j = 0; j < graph[i].size(); j++){
if(r[graph[i][j].u] == false){
k = 1;
dfs1(graph[i][j].u, s + graph[i][j].w, p);
}
}
if(k == 0){
if(s > vs){
v = i;
vs = s;
}
return;
}
}
int main()
{
int n;
while(cin >> n){
for(int i = 0; i <= n+4; i++){
graph[i].clear();
p1[i] = 0;
p2[i] = 0;
}
for(int i = 2; i <= n; i++){
int t1, t2;
edge temp;
cin >> t1 >> t2;
temp.u = t1;
temp.w = t2;
graph[i].push_back(temp);
temp.u = i;
graph[t1].push_back(temp);
}
memset(r, 0, sizeof(r));
v = 0; vs = 0;
dfs1(1,0,nullptr);
memset(r,0,sizeof(r));
int tv = v; v = 0; vs = 0;
dfs1(tv,0,p1);
memset(r,0,sizeof(r));
tv = v; v = 0; vs = 0;
dfs1(tv,0,p2);
for(int i = 1; i <= n; ++i){
if(p1[i] > p2[i])
cout << p1[i] << "\n";
else
cout << p2[i] << "\n";
}
}
return 0;
}
B - 戴好口罩!
题意
给定 名学生, 个群体,学生0受到感染,找出所有需要隔离的学生。
解题思路
用并查集将所有互相接触过的学生加入一个子集中,最后找出学生0所在子集输出答案即可。
代码
#include <iostream>
using namespace std;
int f[100005];
int find(int k){
if (f[k] == k) return k;
return f[k] = find(f[k]);
}
void init(){
for(int i = 0; i < 100005; i++)
f[i] = i;
}
int main()
{
int n, m;
while(cin >> n >> m){
if(n == 0 && m == 0) break;
init();
while(m--){
int num;
cin >> num;
int t1, t2;
cin >> t1;
num--;
while(num--){
cin >> t2;
if(find(t2) != find(t1))
f[find(t2)] = find(t1);
}
}
int ans = 0;
for(int i = 0; i < n; i++){
if(find(i) == find(0))
ans++;
}
cout << ans << endl;
}
return 0;
}
C - 掌握魔法の东东 I
题意
东东在老家农村无聊,想种田。农田有
块,编号从
~
。种田要灌氵
众所周知东东是一个魔法师,他可以消耗一定的 MP 在一块田上施展魔法,使得黄河之水天上来。他也可以消耗一定的 MP 在两块田的渠上建立传送门,使得这块田引用那块有水的田的水。 (
)
黄河之水天上来的消耗是
,
是农田编号 (
)
建立传送门的消耗是
,
是农田编号
东东为所有的田灌氵的最小消耗
解题思路
- 本题可以看做 块农田加上天一共 个点的最小生成树问题。
- 天这个点和任何一个农田都有边。
- 向边集中添加边时注意只需添加矩阵的一半,最后跑一下Kruskal即可。
代码
#include <iostream>
#include <algorithm>
using namespace std;
int f[310];
int k, n, ans;
struct edge{
int u, v, w;
}e[200000];
void make_edge(int u, int v, int w, int i){
e[i].u = u;
e[i].v = v;
e[i].w = w;
}
int find(int k){
if (f[k] == k) return k;
return f[k] = find(f[k]);
}
bool cmp(edge a, edge b){
return a.w < b.w;
}
void kruskal(){
int cnt = 0;
for(int i = 0; i < k; i++){
if(find(e[i].u) != find(e[i].v)){
f[find(e[i].u)] = find(e[i].v);
ans += e[i].w;
cnt++;
}
if(cnt == n)
break;
}
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++){
f[i] = i;
int weight;
cin >> weight;
make_edge(0,i,weight,k++);
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
int temp;
cin >> temp;
if(j > i)
make_edge(i,j,temp,k++);
}
}
sort(e, e + k, cmp);
kruskal();
cout << ans << endl;
return 0;
}
D - 数据中心
题意
解题思路
- 不知道是题面出错了还是什么,就是道裸的最小生成树,记录一下最后加入生成树的边即可。
- 光看题目描述,让我求root到任意一点的最长距离最短的生成树?这怎么做嘛。
- 看了眼样例,emmmmm?和想象中的题目不一样,好像就是个裸的最小生成树?
- 交了一发A了…?黑人问号
代码
#include <iostream>
#include <algorithm>
using namespace std;
int f[50005];
int k, n, ans;
struct edge{
int u, v, w;
}e[100005];
void make_edge(int u, int v, int w, int i){
e[i].u = u;
e[i].v = v;
e[i].w = w;
}
int find(int k){
if (f[k] == k) return k;
return f[k] = find(f[k]);
}
bool cmp(edge a, edge b){
return a.w < b.w;
}
int kruskal(){
int cnt = 0;
for(int i = 0; i < k; i++){
if(find(e[i].u) != find(e[i].v)){
f[find(e[i].u)] = find(e[i].v);
ans += e[i].w;
cnt++;
}
if(cnt == n - 1){
return i;
}
}
return k-1;
}
int main()
{
int m, root;
cin >> n >> m >> root;
for(int i = 1; i <= n; i++)
f[i] = i;
while(m--){
int u,v,w;
cin >> u >> v >> w;
make_edge(u,v,w,k++);
}
sort(e, e + k, cmp);
cout << e[kruskal()].w << endl;
return 0;
}