[MSSB]并查集求连通块

分析

特征

  1. 联通块个数或连通性
  2. 动态联通或删除联通关系,但是不能两种操作一起来

对应算法

利用并查集对集合合并的高效性来解决
如果是删除联通关系,那么就把时间轴翻转过来进行合并操作

题目

1.无线网络

Description

有一个由n台计算机组成的无线网络。(n <= 1001),正常情况下,每台计算机都能跟与它距离不超过d的任何计算机通讯(d <= 20000)。地震发生了。所有的计算机都陷入瘫痪。专家们试着一台一台地修复计算机,以恢复整个无线网络。有时在修复的过程中,他们需要测试一下某两台计算机能否通讯(如果他们能通过别的正常的计算机进行通讯,也算他们之间可以通讯,即“能否通讯”可以是间接的)。
你的任务,就是模拟修复网络的过程,并回答“能否通讯”的询问。
Input

第一行两个整数,N和d,N表示计算机的数目,d表示两台计算机直接可直接通讯的最大距离。接下来的N行,每行两个整数Xi,Yi,表示每台计算机的坐标。接下来有许多行,每行都是一个操作(或者是修复操作,或者是询问操作)。
操作的格式如下:
O p (1 <= p <= N) 修复操作,表示修复编号为p的电脑;
S p q (1 <= p, q <= N) 询问操作,询问编号为p和编号为q的电脑能否通讯。
如果一台电脑尚未被修复,则它不能和任何电脑通讯。
Output

对于每个询问操作:如果能够通讯,输出一行SUCCESS;如果无法通讯,输出一行FAIL
Sample Input

4 1
0 1
0 2
0 3
0 4
O 1
O 2
O 4
S 1 4
O 3
S 1 4
Sample Output

FAIL
SUCCESS
[Hint]
【限制】
对于50%的数据,N <= 300, 操作次数 <= 10000;
对于100%的数据,N <= 1001, 操作次数 <= 300000。

#include<bits/stdc++.h>
using namespace std;
struct computer{int x;int y;int f;int state;};
computer net[1005];
int numOFcomputer,maxdistance;
void init()
{
    freopen("datain2.txt","r",stdin);
}
void datasetting()
{
    scanf("%d%d",&numOFcomputer,&maxdistance);
    for(int i=0;i<numOFcomputer;i++)
    {
        scanf("%d%d",&net[i].x,&net[i].y);
        net[i].f=i;
        net[i].state=0;
    }
    scanf("\n");
}
bool Distance(computer a,computer b)
{
    long long int q,w;
    q=maxdistance*maxdistance;
    w=(a.y-b.y)*(a.y-b.y)+(a.x-b.x)*(a.x-b.x);
    if(q>=w)return true;
    else return false;
}
int findroot(int position)
{
    if(net[position].f==position)return position;
    net[position].f=findroot(net[position].f);
    return net[position].f;
}
void reborn(int a)
{
    net[a].state=1;
    for(int i=0;i<numOFcomputer;i++)
    {
        if(net[i].state==1&&Distance(net[i],net[a]))
        {
            net[findroot(i)].f=findroot(a);
        }
    }
    return;
}
void check(int pox,int poy)
{
    if(findroot(pox)==findroot(poy)&&net[pox].state*net[poy].state)printf("SUCCESS\n");
    else printf("FAIL\n");
    return;
}
void run()
{
    char op;
    while(scanf("%c",&op)!=EOF)
    {
        if(op=='O')
        {
            int a;
            scanf("%d\n",&a);
            a--;
            reborn(a);
        }
        else if(op=='S')
        {
            int x;int y;
            scanf("%d%d\n",&x,&y);
            x--;y--;
            check(x,y);
        }
    }
}
int main()
{
    init();
    datasetting();
    run();
    return 0;
}

2.星球大战

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzkwNzgwMg==,size_16,color_FFFFFF,t_70

>>>>>>>>>>>>>>>>>>>题解

3.岛屿

在这里插入图片描述

在这里插入图片描述

#include <iostream>
#include <fstream>
#include <cstdio>
#include <cmath>
#include <map>
#include <set>
#include <bitset>
#include <ctime>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
using namespace std;
#pragma GCC optimize(2)
#define loop(i,start,end) for(int i=start;i<=end;++i)
#define anti_loop(i,start,end) for(int i=start;i>=end;--i)
#define clean(arry,num) memset(arry,num,sizeof(arry))
#define ll long long
#define isdegit(a) (a>='0'&&a<='9')

template<typename T>void read(T &x){
    char r=getchar();T neg=1;x=0;
    while(!isdegit(r)){if(r=='-')neg=-1;r=getchar();}
    while(isdegit(r)){x=(x<<1)+(x<<3)+r-'0';r=getchar();}
    x*=neg;
}

const int maxn=1000+10,maxm=1000+10,maxt=100000+10;
int h[maxn][maxm];
int T[maxt];
int fa[maxn*maxm];
int n,m,t;
int res[maxt];

int findfa(int u){
    return fa[u]=((fa[u]==u)?u:findfa(fa[u]));
}
inline void merge(int u,int v){
    fa[findfa(u)]=findfa(v);
}

struct node{
    int xi;
    int yi;
    int hi;
    node():xi(0),yi(0),hi(0){}
    node(int xi,int yi,int hi):xi(xi),yi(yi),hi(hi){}
}G[maxn*maxm];
inline bool cmp(node a,node b){
    return a.hi>b.hi;
}

int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
bool vis[maxn][maxm];

void dfs(int x,int y,int hi){
    loop(i,0,3){
        int nx=x+dx[i];
        int ny=y+dy[i];
        if(nx*ny&&nx<=n&&ny<=m&&!vis[nx][ny]&&h[nx][ny]>hi){
            vis[nx][ny]=true;
            dfs(nx,ny,hi);
        }
    }   
}

bool ava[maxn*maxm];
#define id(x,y) ((m*(x-1)+y))
int main(){
    #ifndef ONLINE_JUDGE
    freopen("datain.txt","r",stdin);
    #endif
    clean(vis,false);
    clean(res,0);
    clean(ava,0);
    
    read(n);
    read(m);
    loop(i,1,n){
        loop(j,1,m){
            read(h[i][j]);
            G[id(i,j)]=node(i,j,h[i][j]);
            fa[id(i,j)]=id(i,j);
        }
    }
    
    sort(G+1,G+1+id(n,m),cmp);
    
    int si=0;
    
    read(t);
    loop(i,1,t){
        read(T[i]);
        if(T[i]<G[1].hi){
            si=i;
        }
    }
    
    int col=0;
    int maxx=-1;
    loop(i,1,n){
        loop(j,1,m){
            maxx=max(maxx,h[i][j]);
            if(h[i][j]>T[si]&&!vis[i][j]){
                dfs(i,j,T[si]);
                ++col;
            }
        }
    }
    res[si]=col;
    
    loop(i,1,n){
        loop(j,1,m){
            if(vis[i][j]){
                loop(k,0,3){
                    if(vis[i+dx[k]][j+dy[k]]){
                        merge(id(i,j),id(i+dx[k],j+dy[k]));
                    }
                }
            }
        }
    } 
    
    int p=1;
    while(G[p].hi>T[si]){
        ava[id(G[p].xi,G[p].yi)]=true;
        ++p;
    }
    anti_loop(i,si-1,1){//倒序枚举时间 
        while(G[p].hi>T[i]){//如果点p的高度在当前时间以上 
            ++col;//增加一个连通块 
            ava[id(G[p].xi,G[p].yi)]=true;
            int nx,ny;
            loop(k,0,3){//连接四周的点(nx,ny)
                nx=G[p].xi+dx[k];
                ny=G[p].yi+dy[k];
                if(nx*ny&&nx<=n&&ny<=m&&h[nx][ny]>T[i]&&ava[id(nx,ny)]){
                    if(findfa(id(nx,ny))!=findfa(id(G[p].xi,G[p].yi))){
                        merge(id(nx,ny),id(G[p].xi,G[p].yi));
                        --col;
                    }       
                }
            }
            ++p;
        }
        res[i]=col;
    }
    loop(i,1,t)
        printf("%d ",res[i]);
    
    return 0;
}

转载于:https://www.cnblogs.com/andrew82/p/11372305.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值