Codeforces Round #405 Bear and Friendship Condition 並查集

題目:

A. Bear and Friendship Condition
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Bear Limak examines a social network. Its main functionality is that two members can become friends (then they can talk with each other and share funny pictures).

There are n members, numbered 1 through nm pairs of members are friends. Of course, a member can't be a friend with themselves.

Let A-B denote that members A and B are friends. Limak thinks that a network is reasonable if and only if the following condition is satisfied: For every three distinct members (XYZ), if X-Y and Y-Zthen also X-Z.

For example: if Alan and Bob are friends, and Bob and Ciri are friends, then Alan and Ciri should be friends as well.

Can you help Limak and check if the network is reasonable? Print "YES" or "NO" accordingly, without the quotes.

Input

The first line of the input contain two integers n and m (3 ≤ n ≤ 150 000) — the number of members and the number of pairs of members that are friends.

The i-th of the next m lines contains two distinct integers ai and bi (1 ≤ ai, bi ≤ n, ai ≠ bi). Members aiand bi are friends with each other. No pair of members will appear more than once in the input.

Output

If the given network is reasonable, print "YES" in a single line (without the quotes). Otherwise, print "NO" in a single line (without the quotes).

Examples
input
4 3
1 3
3 4
1 4
output
YES
input
4 4
3 1
2 3
3 4
1 2
output
NO
input
10 4
4 3
5 10
8 9
1 2
output
YES
input
3 2
1 2
2 3
output
NO

這個題就是問對於每個聯通分量,是不是完全圖。

我們可以通過並查集來處理連通分量的問題,例如求連通分量的個數就是求根節點的個數。求這個連通分量中有多少個點,就是求根節點與多少個點相鄰(包括根節點本身)。判斷每個連通分量是不是完全圖,可以通過判斷這個連通分量中的每個點的度數是否等於與根節點相鄰點數-1。

code:61ms

#include<cstdio>
const int MAXN=1.5e5+5;
int par[MAXN],r[MAXN],top[MAXN];
int find(int x){
    return par[x]==x?par[x]:par[x]=find(par[x]);
}
void unit(int x,int y){
    x=find(x);
    y=find(y);
    if(x!=y)par[x]=y;
}
int main(){
    int n,m;scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)par[i]=i;
    for(int i=0;i<m;++i){
        int a,b;scanf("%d%d",&a,&b);
        r[a]++;
        r[b]++;//r記錄每個點的度數
        unit(a,b);
    }
    for(int i=1;i<=n;++i){
        int x=find(i);
        top[x]++;//記錄每個根節點與多少個點相連。
    }
    for(int i=1;i<=n;++i){
        int x=find(i);
        if(r[i]!=top[x]-1){
            printf("NO\n");
            return 0;
        }
    }
    printf("YES\n");
    return 0;
}

另外一種寫法是構造圖,然後通過dfs來找連通塊。

code:77ms

/*暨通過計算每一個連通塊如果是完全圖那麼應該有多少條邊
  再與題目已知邊數進行比較
*/
#include<cstdio>
#include<cstring>
const int MAXN=2e5;
struct edge{int v,next;}es[MAXN*2];
int head[MAXN],tot;
bool visit[MAXN],has[MAXN];
long long t;
void init(){
    tot=0;
    memset(head,-1,sizeof(head));
}
void addEdge(int a,int b){
    es[tot].v=b;
    es[tot].next=head[a];
    head[a]=tot++;
}
void dfs(int no){
    t++;
    visit[no]=true;
    for(int i=head[no];i!=-1;i=es[i].next){
        if(!visit[es[i].v])dfs(es[i].v);
    }
}
int main(void){
    int n,m;scanf("%d%d",&n,&m);
    init();
    memset(visit,false,sizeof(visit));
    memset(has,false,sizeof(has));
    for(int i=0;i<m;++i){
        int a,b;scanf("%d%d",&a,&b);
        has[a]=true;has[b]=true;
        addEdge(a,b);
        addEdge(b,a);
    }
    bool noAns=false;
    long long sum=0;
    for(int i=1;i<=n;++i){
        if(has[i]&&!visit[i]){
            t=0;
            dfs(i);
            sum+=t*(t-1);
            //printf("t=%d\n",t);
        }
    }
    if(sum==2*m)printf("YES\n");
    else printf("NO\n");
}

這個方法的構圖方式可以換一換用容器來寫,感覺這樣比較好看一些://來源:ACM進階之路

code:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=150000+100;
int b[N];
int vis[N];
vector<int>vc[N];//定義一個向量
ll t;
void DFS(int x)
{
    t++;//計算有關的節點沒有被標記過
    vis[x]=1;
    for(int j=0;j<vc[x].size();j++)
    {
        if(vis[vc[x][j]]==0)//如果和它相連的點沒有被標記,
        DFS(vc[x][j]);
    }
}
int main()
{
    int m,n;
    int x,y;
    scanf("%d%d",&n,&m);
    memset(vis,0,sizeof(vis));
    memset(b,0,sizeof(b));
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&x,&y);
        vc[x].push_back(y);//找到x和y的關係
        vc[y].push_back(x);
        b[x]=1;
        b[y]=1;
    }
    ll sum=0;
    for(int i=1;i<=n;i++)
    {
        if(vis[i]==0&&b[i])
        {
            t=0;
            DFS(i);
            sum=sum+t*(t-1);//(t-1)*t求邊數,完全圖
        }
    }
    if(2*m!=sum)cout<<"NO"<<endl;//N個完全圖的邊數等於m個節點所構成的邊數
    else
        cout<<"YES"<<endl;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章