某近似模板题1

P2097 资料分发1
题目描述

有一些电脑,一部分电脑有双向数据线连接。如果一个电脑得到数据,它可以传送到的电脑都可以得到数据。现在,你有这个数据,问你至少将其输入几台电脑,才能使所有电脑得到数据。

输入输出格式

输入格式:
第一行两个数n,m。n是点数,m是边数。

接下来m行,每行2个整数p,q表示p到q有一条双向数据线。

输出格式:
一个整数,表示至少输入的电脑数量。

输入输出样例

输入样例#1: 复制
4 5
1 2
1 3
2 3
2 1
3 4
输出样例#1: 复制
1
说明

对于30%的数据:n<=100,m<=1000

对于60%的数据:n<=2000,m<=100000

对于100%的数据:n<=100000, m<=200000

数据不保证没有重边,不保证没有自回环

用时168-92-68-56ms

看到有人用Tarjan求强联通分量做
23333
dfs,复杂度O(n)
并查集,复杂度O(input左右)
路径压缩,读入优化

#include<iostream>
#include<cstdio>
#define N 100005
using namespace std;

int a,b;
int n,m;
int fa[N];
int siz[N];

void init(){
    for(int i=1;i<=n;++i)
        fa[i]=i;
    for(int i=1;i<=n;++i)
        siz[i]=1;
}

int find(int s){
    if(fa[s]!=s)fa[s]=find(fa[s]);
    return fa[s];
}

void read(int &s){
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar());
    for(s=0;isdigit(ch);s=s*10+ch-'0',ch=getchar());
}

int faa,fab;

bool un(int a,int b){
    faa=find(a);
    fab=find(b);
    if(faa>fab){
        faa^=fab;
        fab^=faa;
        faa^=fab;
    }
    if(faa!=fab)return fa[faa]=fab,siz[fab]+=siz[faa];
    return false;
}

int ans;

int main(){
    while(~scanf("%d%d",&n,&m)){
        init();ans=n; 
        for(int i=1;i<=m;++i){
            read(a),read(b);
            if(un(a,b))ans--;
        }
        printf("%d\n",ans);
    }
    return 0;
}
posted @ 2017-11-19 09:22  Grary  阅读(149)  评论(0编辑  收藏  举报
博客园 首页 私信博主 编辑 关注 管理 新世界