【并查集】HDU 4496 D-City

HDU 4496 D-City                                                                                          

D-City

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 5189    Accepted Submission(s): 1822
  题目链接->http://acm.hdu.edu.cn/showproblem.php?pid=4496

Problem Description
Luxer is a really bad guy. He destroys everything he met. 
One day Luxer went to D-city. D-city has N D-points and M D-lines. Each D-line connects exactly two D-points. Luxer will destroy all the D-lines. The mayor of D-city wants to know how many connected blocks of D-city left after Luxer destroying the first K D-lines in the input. 
Two points are in the same connected blocks if and only if they connect to each other directly or indirectly.

Input
First line of the input contains two integers N and M. 
Then following M lines each containing 2 space-separated integers u and v, which denotes an D-line. 
Constraints: 
0 < N <= 10000 
0 < M <= 100000 
0 <= u, v < N. 
 
Output
Output M lines, the ith line is the answer after deleting the first i edges in the input.
 
Sample Input
  5 10 
  0 1 
  1 2 
  1 3 
  1 4 
  0 2 
  2 3 
  0 4 
  0 3 
  3 4 
  2 4

Sample Output

  1 
  1 
  1 
  2 
  2 
  2 
  2 
  3 

  4 

  5

 Problem Idea

 【题意】

    题意为:给出一个有N(0<N<=10000)个顶点的无向图(顶点编号0到N-1), 然后依次给出它的M(0<M<=100000)条边,要求当删除已经输入的前k(1<=K<=M)条边后依次输出该图的连通分量总数

    输入:第一行是N和M,然后是M行数(X,Y)(0<=X,Y<N)表示X与Y有边。
    输出:依次输出所求的连通分量数。

 【类型】
  并查集求无向图的连通分量
 【分析】

  并查集模板题,入门。

  题目所求的“当删除前K条边时图所剩的连通分量数” 就是 “向N个孤立点只添加M-K条边后,所具有的连通分量数”
        所以仅需逆序插入每条边,分别保存插入边后新图所具有的连通分量数目在数组内,然后输出数组即可。

 【注意】

  findset函数中return的写法要注意:

  第一次写模板,找了好长时间发现的问题:

 (1)return fa[x]==-1 ? x :fa[x]=findset(fa[x]);而不是return fa[x]==-1 ? x :fa[x]=findset(x);

 (2)return fa[x]==-1 ? x :fa[x]=findset(fa[x]);而不是return fa[x]==-1 ? x :findset(fa[x]);

int findset(int x){//返回x节点的根节点,并把x节点直接挂在根节点下面
    return fa[x]==-1 ? x :fa[x]=findset(fa[x]);
    //如果fa[x]==-1,说明x本身就是根
    //如果fa[x]!=-1,递归调用,返回x的父节点所在树的根
}


 Souce Code

#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
using namespace std;
const int nmax=10000+5;
const int mmax=100000+5;
//并查集基本代码 模板
//fa需要初始化,memeset(fa,-1,sizeof(fa);
int fa[nmax];//fa[i]表示i节点的父节点

int findset(int x){//返回x节点的根节点,并把x节点直接挂在根节点下面
    //return fa[x]==-1 ? x :fa[x]=findset(x); 这一行错了,是fa[x]=findset(fa[x]),不是fa[x]=findset(x)
    return fa[x]==-1 ? x :fa[x]=findset(fa[x]);//也不能写成return fa[x]==-1?x:findset(fa[x]);
    //如果fa[x]==-1,说明x本身就是根
    //如果fa[x]!=-1,递归调用,返回x的父节点所在树的根
}

int bind(int u,int v){//合并u节点和v节点所属的连通分量
    int fu=findset(u);//获取u节点的根
    int fv=findset(v);//获取v节点的根
    if(fu!=fv){//若根不同,属于不同的连通分量,则可合并
        fa[fu]=fv;
        return 1;//连通分量少了1个
    }
    return 0;//若根相同连通分量数不变
}
int main() {
    int n,m;//n个节点,m条边
    while(scanf("%d%d",&n,&m)==2){
        memset(fa,-1, sizeof(fa));//初始化fa数组

        vector<pair<int,int>>vc;//vc按序保存所有的边,记录起点和终点

        for(int i=0;i<m;i++){//依次输入各条边
            int u,v;//起点和终点
            scanf("%d%d",&u,&v);
            vc.push_back(make_pair(u,v));
        }
        vector<int> res;//res数组保存连通分量的数值
        int cnt=n;//cnt记录当前的连通分量数
        res.push_back(cnt);
        //当删除当前已输入的前K条边时图所剩的连通分量数 就是向N个孤立的点只添加M-K条边后,所具有的连通分量数。
        for(int i=m-1;i>=1;i--){//逆序依次连接所有孤立的点,边至少一条
            cnt-=bind(vc[i].first,vc[i].second);
            res.push_back(cnt);
        }

        for(int i=res.size()-1;i>=0;i--){//节点数最小为0
           printf("%d\n",res[i]);
        }
    }

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值