您的位置:首页 > Web前端

解题报告-PAT-File Transfer

2016-10-23 11:01 190 查看

解题报告-PAT-File Transfer

原题链接:https://pta.patest.cn/pta/test/1342/exam/4/question/21732

题意描述:

输入N个节点和一系列字符串序列:

5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
S

其中C表示,判断当前3 2节点是否连通,如果连通输出yes,不连通输出no。

I表示,将节点2 4并到一个集合中。

S表示输入结束。

使用优化的并查集解题:

# include <stdio.h>
# include <cstdio>
# include <iostream>
# define MAX 10100
using namespace std;
int S[MAX];

void Initial(int n){
for(int i=0;i<=n;i++)
S[i] = -1;
}

/*
递归形式可以这么写
int Find(int x){
if(S[x] != x)
S[x]=Find(S[x]);
return S[x];
}
*/

int Find(int x){
int k=x,t; //k表示没合并前的节点。
//在并查集S中查找并返回包含x的树根
while(S[x] >= 0) //根节点的值都是小于零的
x=S[x];
//x节点是根节点
//从k节点开始,k节点到根节点所经过的节点,全都连接到根节点上
while(k != x) {
t=k;
k = S[k];
S[t] = x;
}
return x;
}

int Union(int x,int y){ //启发式合并
int fx,fy;
fx = Find(x);
fy = Find(y);
if(fx!=fy){
// 并到多的一方
if(-(S[fx]) > -(S[fy])){
S[fx] = S[fx] + S[fy];
S[fy] = fx;
}else{
S[fy] = S[fx] + S[fy];
S[fx] = fy;
}
return 1;
}else return 0;//代表 x,y同属于一个集合
}
int main(){
int N,c1,c2;
char m;
cin >> N;
Initial(N);
cin >> m;
while(m!='S'){
scanf("%d %d",&c1,&c2);
if(m=='I'){
Union(c1,c2);
}else{
if(Find(c1) == Find(c2))
printf("yes\n");
else
printf("no\n");
}
cin >> m;
}
int co = 0;
for(int j=1;j<=N;j++){
if(S[j] < 0)
co++;
}
if(co == 1)
printf("The network is connected.\n");
else
printf("There are %d components.\n",co);
return 0;
}注意几个地方:
1)并查集的查找可以改为递归方式,更简洁,但不好理解。

2)输入有可能没有操作,直接输入N之后便输入S结束,这时候输出有N个组成部分。

3)这道题的并查集数组就能搞定,如果需要存储额外的信息,可以参考严蔚敏数据结构的介绍。

# define SIZE 100
//存储结构: 双亲表示法
struct TreeNode{ //节点结构
char nameId; //节点编号A,B,C...也可以是其他类型,也可以加成员
int parent; //双亲位置域,这个是必须的
}TreeNode;
TreeNode treeNode[SIZE+1];

//查操作 路径压缩
int find(TreeNode &treeNode,int x){//确定x所在的子集
if(i<1 || i>100)//>100在实际问题中可以是>n,n为节点总数
return -1;//合法性验证
for(int i=x;treeNode[i].parent>0;i=treeNode[i].parent)
//如果i号节点的双亲节点大于0,表示还没找到根节点,继续找
//路径压缩
for(int k=x;k!=i;k=treeNode[k].parent)//从x节点开始,x节点到根节点经过的所有节点都连接到根节点上。
treeNode[k].parent=i; //经过点的双亲是i,i是上一个循环中找到的集合的根节点

return i;//返回集合根节点
}

//并操作 启发式搜索
void meget(TreeNode &treeNode,int x,int y){
//传过来x,y需要先查询所在的子集
int fx=find(x);
int fy=find(y);
//查询操作也可以放在外面进行,这样就不需要查询,直接合并。
if(treeNode[fx].parent>treeNode[fy].parent) //如果fx集合的元素较少,因为parent节点保存的是集合元素的负值。
{
treeNode[fy].parent += treeNode[fx].parent; //往多的一方合并
treeNode[fx].parent=fy;
}else{
treeNode[fx].parent += treeNode[fx].parent; //往多的一方合并
treeNode[fy].parent=fx;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: