欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

HDU——1272 小希的迷宫(并查集模板题)

程序员文章站 2022-03-15 19:18:20
...

原题链接http://acm.hdu.edu.cn/showproblem.php?pid=1272

HDU——1272 小希的迷宫(并查集模板题)
输入样例

6 8  5 3  5 2  6 4
5 6  0 0

8 1  7 3  6 2  8 9  7 5
7 4  7 8  7 6  0 0

3 8  6 8  6 4
5 3  5 6  5 2  0 0

-1 -1

输出样例

Yes
Yes
No

题意:给你一些关于迷宫的数据,判断是否任意两个房间有且仅有一条路径可以相通(除非走了回头路)。

解题思路:妥妥的一道并查集题目,因为并查集就是将一些点并到一起,即连在一起,若我此时再输入一道数据且这道数据已经连在一起了,那么自然会形成环,使得两个点之间有两条路,说得通一点,这道题就是判断有没有环和有没有把所有的点连在一起,即点集合只有一个
当然还有其它更简单的水题AC法。(可以过但不推荐,题中数据没有给的很刁钻)
我们来说一下怎么水过去,由于样例给的边不会有重复的,所以我们不会形成环还要是强连通图的条件就是边数+1=点数。利用这个再特判一下点全为0的条件。即可水过该题。

并查集AC代码

/*
*邮箱:aaa@qq.com
*blog:https://me.csdn.net/hzf0701
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*
*/
#include<bits/stdc++.h>    //POJ不支持

#define rep(i,a,n) for (int i=a;i<=n;i++)//i为循环变量,a为初始值,n为界限值,递增
#define per(i,a,n) for (int i=a;i>=n;i--)//i为循环变量, a为初始值,n为界限值,递减。
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define fi first
#define se second
#define mp make_pair

using namespace std;

const int inf = 0x3f3f3f3f;//无穷大
const int maxn = 1e5+2;//最大值。
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll>  pll;
typedef pair<int, int> pii;
//*******************************分割线,以上为自定义代码模板***************************************//

int father[maxn];//存储所连结点。
int Find(int x){
    int r=x;
    while(father[r]!=r)
        r=father[r];
    //找到根节点。
    //回溯降低深度。
    int i=x,j;
    while(father[i]!=r){
        j=father[i];
        father[i]=r;
        i=j;
    }
    return r;
}
void Merge(int x,int y){
    //合并x和y。
    int fx=Find(x),fy=Find(y);
    if(fx!=fy)
        father[fx]=fy;
}
int main(){
    //freopen("in.txt", "r", stdin);//提交的时候要注释掉
    IOS;
    int u,v;
    while(1){
        bool flag=false;
        memset(father,0,sizeof(father));//由于顶点编号是随机的,所以我们必需对顶点初始化后为0,再对输入数据进行编号处理。
        while(cin>>u>>v&&(u+v)){
            if(u==-1&&v==-1)return 0;
            if(father[u]==0)father[u]=u;
            if(father[v]==0)father[v]=v;
            if(Find(u)==Find(v)){
                flag=true;//如果它们对应的终点相同,意味着它们已经连通,此时连接这两个点自然存在环。
            }
            else if(!flag)//这里判断flag是因为如果flag为true就已经得到了答案,无须浪费时间。
                Merge(u,v);//连接u,v
        }
        int sum=0;//判断有多少个集合。
        if(flag)
            cout<<"No"<<endl;
        else{
            rep(i,1,maxn){
                if(father[i]==i)sum++;
            }
            if(sum>1)
                cout<<"No"<<endl;
            //说明在两个集合里。
            else 
                cout<<"Yes"<<endl;
        }
    }
    return 0;
}

水题AC代码

/*
*邮箱:aaa@qq.com
*blog:https://me.csdn.net/hzf0701
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*
*/
#include<bits/stdc++.h>	//POJ不支持

#define rep(i,a,n) for (int i=a;i<=n;i++)//i为循环变量,a为初始值,n为界限值,递增
#define per(i,a,n) for (int i=a;i>=n;i--)//i为循环变量, a为初始值,n为界限值,递减。
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define fi first
#define se second
#define mp make_pair

using namespace std;

const int inf = 0x3f3f3f3f;//无穷大
const int maxn = 1e5+2;//最大值。
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll>  pll;
typedef pair<int, int> pii;
//*******************************分割线,以上为自定义代码模板***************************************//

bool vis[maxn];
int cnt1,cnt2;
int main(){
	//freopen("in.txt", "r", stdin);//提交的时候要注释掉
	IOS;
	int u,v;
	while(1){
		cnt1=0;cnt2=0;
		memset(vis,false,sizeof(vis));
		while(cin>>u>>v&&(u+v)){
			if(u==-1&&v==-1)return 0;
			vis[u]=vis[v]=true;
			cnt1++;
		}
		rep(i,1,1e5)
			if(vis[i])cnt2++;
		if(cnt2==0||cnt2==cnt1+1)
			cout<<"Yes"<<endl;
		else
			cout<<"No"<<endl;
	}
	return 0;
}

相关标签: 并查集 HDU