小K的技术

小K的技术

image-20230831084505028

image-20230831084525866

考虑每个弱连通分量(即无视边的方向形成的各个连通分量,内部点彼此可达),答案是独立的。

而且对于一个弱连通分量,若不存在环,我们可以发现其实只需要点数 \(k-1\) 的边数即可,因为原图是 DAG,所以可以让这个类似于一棵树。

而如果存在环,说明依赖关系并不是顺序结构,那么需要多一条边,而且根据一个环一定满足,那么最多也就 \(k\) 条边。

于是,我们对于每个弱连通分量判断是否存在环,如果不存在,答案就减去一。

关于环的判断,可以考虑黑白灰染色。对于每个点,未遍历时标记为 \(0\),第一次遍历时标记为 \(1\),表明它的后继节点没有遍历完成,往后遍历若遇到 \(0\) 则过去遍历,否则如果遇到 \(1\) 标记说明存在环。

#include<cstdio>
#include<cstring>
#define sh short
using namespace std;
#define Ed for(int i=h[x];~i;i=ne[i])
#define Ls(i,l,r) for(int i=l;i<r;++i)
#define Rs(i,l,r) for(int i=l;i>r;--i)
#define Le(i,l,r) for(int i=l;i<=r;++i)
#define Re(i,l,r) for(int i=l;i>=r;--i)
#define L(i,l) for(int i=0;i<l;++i)
#define E(i,l) for(int i=1;i<=l;++i)
#define W(t) while(t--)
#define Wh while

const int N=100010,M=2*N;
int n,m,ans,nidx;
int h[N],e[M],ne[M],idx,st[N];//don't forget memset h!
bool cir[N];
sh vis[N];
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int x){
    st[x]=nidx;
    Ed{
        int j=e[i];
        if(!st[j])dfs(j);
    }
}
bool Dfs(int x){
    vis[x]=1;
    Ed{
        if(i&1)continue;
        int j=e[i];
        if(!vis[j]&&Dfs(j))return 1;
        else if(vis[j]==1)return 1;
    }
    vis[x]=2;
    return 0;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    #endif
    scanf("%d%d",&n,&m);
    memset(h,-1,n*4+4);
    E(i, m){
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);
    }
    int tot=n;
    E(i, n)
        if(!st[i])++nidx,dfs(i);
    E(i, n){
        if(cir[st[i]])continue;
        if(!vis[i])cir[st[i]]=Dfs(i);
    }
    E(i, nidx)tot-=!cir[i];
    printf("%d",tot);
    return 0;
}
posted @ 2023-08-31 08:49  wscqwq  阅读(1)  评论(0编辑  收藏  举报