P2256 一中校运会之百米跑(洛谷)
方法:这是一道赤裸裸的并查集题目,根据输入先进行合并,合并后根据输入开始查询判断即可。需要注意的是,为了简化题目,实际操作过程中可以用编号来对应姓名,从而表示出不同的学生,并建立相应的联系。
实现代码:
#include<bits/stdc++.h> #include <cstring> using namespace std; //一看这个问题是组间分类和查询问题,便可以联想到并查集的方法去解决 //关键在于将字符串用数字来代替处理,然后套上并查集的模板就能直接AC(还好测试数据不是过大,双重循环尽然没崩,lucky.jpg) #define MAX_N 1000005 int n,m; string s[20005]; //储存学生的名字 int rank[MAX_N]; //树的高度 int par[MAX_N]; void init(){ for(int i=1;i<=n;i++){ par[i]=i; rank[i]=0; } } int find(int x){ //查询树的根 if(par[x]==x){ return x; }else return par[x]=find(par[x]); //在查找的过程中实际上直接将父节点连接到根节点上进行优化 } void unite(int x,int y){ x=find(x); y=find(y); if(x==y) return; if(rank[x]<rank[y]){ par[x]=y; }else{ par[y]=x; if(rank[x]==rank[y]) rank[x]++; //两棵树一样高时,合并在x树上后X的高度加1 } } bool same(int x,int y){ return find(x)==find(y); } int k=0; int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ cin>>s[i]; } init(); for(int i=1;i<=m;i++){ //分开来输入 string a,b; cin>>a>>b; //输入关系 int flag1=0,flag2=0; int t1=0,t2=0; for(int j=1;j<=n;j++){ if(s[j]==a){ t1=j; flag1=1; } if(s[j]==b){ t2=j; flag2=1; } if(flag1&&flag2){ break; } } unite(t1,t2); } int k=0; cin>>k; for(int i=1;i<=k;i++){ string a,b; cin>>a>>b; int flag1=0,flag2=0; int t1=0,t2=0; for(int j=1;j<=n;j++){ if(s[j]==a){ t1=j; flag1=1; } if(s[j]==b){ t2=j; flag2=1; } if(flag1&&flag2){ break; } } if(same(t1,t2)){ cout<<"Yes."<<endl; }else cout<<"No."<<endl; } return 0; }