cf789d 图论计数,自环闭环

一开始没有思路,以为要判联通块。

其实不是判断联通块,而是判断边是否连在一起,没有连边的点可以忽略不计

/*
分情况讨论:
1.忽略自环,那么要取出两条相连的普通变作为只经过一次的边 
2.一条自环,一条普通边
3.两条自环 
自环独立存储 
*/
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000005
#define ll long long
struct Edge{
    int to,next;
}edge[maxn<<1];
int n,m,u,v,head[maxn],tot,vis[maxn],degree[maxn],f[maxn],num1,num2;

void dfs(int u){
    vis[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if(!vis[v])dfs(v); 
    }
}

void addedge(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++; 
}

int main(){
    scanf("%d%d",&n,&m);
    memset(head,-1,sizeof head);
    memset(degree,0,sizeof degree);
    memset(f,0,sizeof f);
    memset(vis,0,sizeof vis);
    tot=num1=num2=0;
    
    for(int i=0;i<m;i++){
        scanf("%d%d",&u,&v);
        if(v==u)f[u]=1,num1++;
        else {
            addedge(u,v);
            addedge(v,u);
            num2++;
            degree[u]++;
            degree[v]++;
        }
    } 
    
    for(int i=1;i<=n;i++)
        if(degree[i]){//从第一个和其他点有边的点开始 
            dfs(i);break;
        }
    for(int i=1;i<=n;i++)
        if(!vis[i] && (degree[i] || f[i])){
            puts("0");return 0;
        } 
    
    ll ans=0;
    for(int i=1;i<=n;i++)
        ans+=(ll)degree[i]*(degree[i]-1)/2;
    ans+=(ll)num1*num2+(ll)num1*(num1-1)/2;
    printf("%lld
",ans); 
}
原文地址:https://www.cnblogs.com/zsben991126/p/10207487.html