A - 氪金带东
问题描述:
思路:
这道题因为要找到所有点到其他点的距离的最大值,所以肯定要先找到树的直径的两个端点,这样其他点到出自己点之外的所有点的距离的最大值则一定是到这两个端点的最大距离的比较大的那一个,所有先用两个dfs来找到这两个端点,并且在第二个dfs时就可记录第一个端点到其他点的距离的最大值,然后第三个dfs找到第二个端点到其他点的距离的最大值,最后比较输出即可。
#include <iostream>
using namespace std;
int n;
struct edge
{
int u,v,w,next;
}A[20040];
int head[10010],tot=0;
bool vis[10010],vis1[10010],vis2[10010];
int point1=0;
int maxlen=0,maxlen1=0;
int result[10010],result1[10010],aa[10010];
void addedge(int u,int v,int w)
{
A[tot].u=u;A[tot].v=v;A[tot].w=w;A[tot].next=head[u];
head[u]=tot;
tot++;
}
void dfs(int a)//找到一个端点
{
vis[a]=1;
for(int i=head[a];i!=-1;i=A[i].next)
{
if(vis[A[i].v]==0)
{
vis[A[i].v]=1;
aa[A[i].v]=aa[a]+A[i].w;
if(aa[A[i].v]>maxlen1)
{
maxlen1=aa[A[i].v];
point1=A[i].v;
}
dfs(A[i].v);
}
}
}
void dfs1(int a)//找到直径的令一个端点,并记录该上一个断点到树里面所有点的最大距离
{
vis1[a]=1;
for(int i=head[a];i!=-1;i=A[i].next)
{
if(vis1[A[i].v]==0)
{
vis1[A[i].v]=1;
result[A[i].v]=result[a]+A[i].w;
if(result[A[i].v]>maxlen)
{
maxlen=result[A[i].v];
point1=A[i].v;
}
dfs1(A[i].v);
}
}
}
void dfs2(int a)//记录后一个端点到树里面所有点的最大距离
{
vis2[a]=1;
for(int i=head[a];i!=-1;i=A[i].next)
{
if(vis2[A[i].v]==0)
{
vis2[A[i].v]=1;
result1[A[i].v]=A[i].w+result1[a];
dfs2(A[i].v);
}
}
}
void cs()
{
while(cin>>n)
{
maxlen=0;maxlen1=0;point1=0;tot=0;
for(int i=0;i<10010;i++)
{
result[i]=0;result1[i]=0;vis[i]=0;vis1[i]=0;vis2[i]=0;aa[i]=0;
head[i]=-1;
}
int y=0,y1=0;
int a,b;
for(int i=2;i<=n;i++)
{
cin>>a>>b;
addedge(i,a,b);
addedge(a,i,b);
}
vis[1]=1;
dfs(1);
y=point1;
vis1[y]=1;
dfs1(y);
y1=point1;
vis2[y1]=1;
dfs2(y1);
for(int i=1;i<=n;i++)
{
cout<<max(result[i],result1[i])<<endl;//比较两个端点到树中点的距离进行输出
}
}
}
int main(int argc, char** argv)
{
cs();
return 0;
}
B - 戴好口罩!
问题描述:
思路:
这道题就是一个简单的并查集的问题,在将所有集合合并之后,找到含有零号病人的集合有多少人即可,所以这道题不难,细心一点就好。
#include <iostream>
using namespace std;
int n=0,m=0;
int parent[30010],rnk[30010];
int find(int x)
{
return parent[x]==x?x:parent[x]=find(parent[x]);
}
bool unite(int x,int y)
{
x=find(x);
y=find(y);
if(x==y)
{
return false;
}
else
{
parent[x]=y;
rnk[y]=rnk[y]+rnk[x];
return true;
}
}
void cs()
{
while(cin>>n>>m&&(n!=0||m!=0))
{
for(int i=0;i<30010;i++)
{
parent[i]=i;
rnk[i]=1;
}
for(int i=0;i<m;i++)
{
int n1,a=0;
cin>>n1;
for(int i1=0;i1<n1;i1++)
{
int a1;
cin>>a1;
if(i1!=0)
{
unite(a,a1);
}
a=a1;
}
}
cout<<rnk[find(0)]<<endl;//输出零号病人的集合共有多少人
}
}
int main(int argc, char** argv)
{
cs();
return 0;
}
C - 掌握魔法の东东 I
问题描述:
思路:
这道题总体的思路是最小生成树,因为比正常情况多了黄河水,所以把这部分可以作为万能点,能与所有点相连接,然后再用最小生成树求解就行。
#include <iostream>
#include<algorithm>
using namespace std;
int n,tot=0,father[100010];
struct edge1
{
int u,v,w;
bool operator < (const edge1 &x)
{
return this->w<x.w;
}
}edge[90010];
int find(int x)
{
if(father[x]==x)
{
return x;
}
return father[x]=find(father[x]);
}
bool unite(int x,int y)
{
x=find(x);
y=find(y);
if(x==y)return false;
else
{
father[y]=x;
return true;
}
}
int ans=0;
void kruskal()
{
sort(edge,edge+tot);
int cnt=0;
for(int i=0;i<tot;i++)
{
if(unite(edge[i].u,edge[i].v))
{
ans=ans+edge[i].w;
cnt++;
if(cnt==n)
{
return;
}
}
}
}
void cs()
{
cin>>n;
for(int i=0;i<=n;i++)
{
father[i]=i;
}
for(int i=1;i<=n;i++)
{
cin>>edge[tot].w;
edge[tot].v=i;edge[tot].u=0;
tot++;
}
for(int i=1;i<=n;i++)
{
for(int i1=1;i1<=n;i1++)
{
cin>>edge[tot].w;
if(edge[tot].w!=0)
{
edge[tot].u=i;edge[tot].v=i1;tot++;
}
}
}
kruskal();
cout<<ans;
}
int main(int argc, char** argv)
{
cs();
return 0;
}
D - 数据中心
问题描述:
思路:
这道题的难度比上道题还简单,直接应用最小生成树,然后找到最小生成树里面的最大边就算完成了。
#include <iostream>
#include<algorithm>
using namespace std;
int father[50005];
struct edge
{
int u,v,w;
bool operator < (const edge &x)
{
return this->w<x.w;
}
}A[100005];
int n,tot=0,max1=0;
int find(int x)
{
if(father[x]==x)
{
return x;
}
return father[x]=find(father[x]);
}
bool unite(int x,int y)
{
x=find(x);
y=find(y);
if(x==y)return false;
else
{
father[y]=x;
return true;
}
}
void kruskal()
{
sort(A,A+tot);
int cnt=0;
for(int i=0;i<tot;i++)
{
if(unite(A[i].u,A[i].v))
{
max1=max(max1,A[i].w);
if(++cnt==n-1)return;
}
}
}
void cs()
{
int m,root;
cin>>n>>m>>root;
for(int i=0;i<=n;i++)
{
father[i]=i;
}
int a,b,c;
for(int i=0;i<m;i++)
{
cin>>a>>b>>c;
A[tot].u=a;
A[tot].v=b;
A[tot].w=c;
tot++;
}
kruskal();
cout<<max1;
}
int main(int argc, char** argv)
{
cs();
return 0;
}