1. 程式人生 > >某近似模板題1

某近似模板題1

find %d mes isdigit stream 分發 得到 cnblogs pre

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;
}

某近似模板題1