题目描述

给你一张有向图,求:

1. 图中最大强连通分量的大小
2. 至少加多少条边才能够让其变成一张强连通图
3. 一种加边的方案

数据范围

$n \leq 10^4,m \leq 2 \times 10^5$,至少要加的边数小于等于 1000.

题目分析

首先 tarjan 跑一次缩点,轻松求出第一问(以下的 “点” 皆表示缩点后的点)
第二问的答案是 max(只有入度为 0 的点数,只有出度为 0 的点数)+孤点(出入度都为 0)(另外,如果本图就是强连通图,那当然答案是 0)
那么这是为什么呢,看了构造方法就知道了。

加边方案怎么求呢?
随机化瞎搞,请 boshi 同学开始 TA 的表演
贪心瞎搞,请 xzy 同学开始 TA 的表演
二分图匹配。

首先,每个入度为 0 的点都要有一个点到它,每个出度为 0 的点都要到一个点,这种性质让我们联想到美丽的二分图。我们先把孤点扔掉,然后建立一个二分图,一边为出度为 0 的点,一边为入度为 0 的点,然后如果某一个出度为 0 的点可以到达入度为 0 的点,它们之间就有一条边。用匈牙利算法跑一次匹配。

然后匹配完之后,大概是这样的:
$a_1$——>$b_1$
$a_2$——>$b_2$

$a_n$——>$b_n$
连边:
$b_1$——>$a_2$
$b_2$——>$a_3$

$b_n$——>$a_1$
这样就形成了一个环,环当然是强连通分量。然后没有匹配上点的那些 single dog 们呢,如果它是出度为 0 的点,那么一定有一个环上的点到它。如果它是入度为 0 的点,那么一定到一个环上的点。所以我们只要在它们之间任意连一些边就强连通了。

至于孤点,将环从某处断开,接上去即可。

注意全是孤点的情况。

代码

#include<bits/stdc++.h>
using namespace std;
#define RI register int
int read() {
    int q=0;char ch=' ';
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
    return q;
}
const int N=10005,M=200005;
int n,m,tot,now,top,cnt,ans1;
int h[N],ne[M],to[M],dfn[N],low[N],st[N],ins[N];
int col[N],bj[N],sz[N],cd[N],rd[N];

void add(int x,int y) {to[++tot]=y,ne[tot]=h[x],h[x]=tot;}
void tarjan(int x) {//tarjan 大法好
    dfn[x]=low[x]=++now,st[++top]=x,ins[x]=1;
    for(RI i=h[x];i;i=ne[i])
        if(!dfn[to[i]]) tarjan(to[i]),low[x]=min(low[x],low[to[i]]);
        else if(ins[to[i]]) low[x]=min(low[x],dfn[to[i]]);
    if(dfn[x]==low[x]) {
        ++cnt,bj[cnt]=x;
        while(st[top]!=x)
            col[st[top]]=cnt,++sz[cnt],ins[st[top]]=0,--top;
        col[x]=cnt,++sz[cnt],ins[st[top]]=0,--top;
    }
}

vector<int> G[N],B[N];
int r0[N],c0[N],QAQ[N],vis[N],cp[N],QvQ[N],dog[N],cg[N];
int js1,js2,js3,orz,STO;
void dfs(int x,int st) {//寻找每一个入度为 0 点可达的出度为 0 点
    if(cd[x]==0) B[st].push_back(x);
    for(RI i=0;i<cd[x];++i)
        if(cg[G[x][i]]!=st) cg[G[x][i]]=st,dfs(G[x][i],st);
}
int Nico(int x) {//二分图匹配
    for(RI i=0;i<B[x].size();++i) 
        if(!vis[B[x][i]]) {
            vis[B[x][i]]=1;
            if(!cp[B[x][i]]||Nico(cp[B[x][i]])) {
                cp[B[x][i]]=x,cp[x]=B[x][i];
                return 1;
            }
        }
    return 0;
}
void work() {
    for(RI i=1;i<=cnt;++i)
        if(!rd[i]&&!cd[i]) QAQ[++js3]=i;
        else if(!rd[i]) r0[++js1]=i;
        else if(!cd[i]) c0[++js2]=i;
    printf("%d\n",max(js1,js2)+js3);
    for(RI i=1;i<=js1;++i) dfs(r0[i],r0[i]);
    for(RI i=1;i<=js1;++i) {
        for(RI j=1;j<=js2;++j) vis[c0[j]]=0;
        Nico(r0[i]);
    }
    for(RI i=1;i<=js1;++i)
        if(!cp[r0[i]]) dog[++STO]=r0[i];//处理单身狗
        else QvQ[++orz]=r0[i];
    for(RI i=1;i<=js2;++i)
        if(!cp[c0[i]]) {
            if(STO) printf("%d %d\n",bj[c0[i]],bj[dog[STO]]),--STO;//优先单身狗与单身狗牵手
            else printf("%d %d\n",bj[c0[i]],bj[r0[1]]);
        }
    while(STO) printf("%d %d\n",bj[c0[1]],bj[dog[STO]]),--STO;//乱连边
    if(orz) {//断开环接上孤点
        for(RI i=1;i<orz;++i)
            printf("%d %d\n",bj[cp[QvQ[i]]],bj[QvQ[i+1]]);
        int las=cp[QvQ[orz]];
        for(RI i=1;i<=js3;++i) printf("%d %d\n",bj[las],bj[QAQ[i]]),las=QAQ[i];
        printf("%d %d\n",bj[las],bj[QvQ[1]]);
    }
    else {//只有孤点的情况
        for(RI i=1;i<js3;++i) printf("%d %d\n",bj[QAQ[i]],bj[QAQ[i+1]]);
        printf("%d %d\n",bj[QAQ[js3]],bj[QAQ[1]]);
    }
}

int main()
{
    freopen("scg.in","r",stdin);
    freopen("scg.out","w",stdout);
    int x,y;
    n=read(),m=read();
    for(RI i=1;i<=m;++i) x=read(),y=read(),add(x,y);
    for(RI i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
    for(RI i=1;i<=cnt;++i) ans1=max(ans1,sz[i]);
    printf("%d\n",ans1);
    if(cnt==1) {puts("0");return 0;}
    for(RI i=1;i<=n;++i)
        for(RI j=h[i];j;j=ne[j])
            if(col[i]!=col[to[j]]) G[col[i]].push_back(col[to[j]]);
    for(RI i=1;i<=cnt;++i) {
        sort(G[i].begin(),G[i].end());
        G[i].erase(unique(G[i].begin(),G[i].end()),G[i].end());
        cd[i]=G[i].size();
        for(RI j=0;j<cd[i];++j) ++rd[G[i][j]];
    }
    work();
    return 0;
}
分类: 文章

litble

苟...苟活者在淡红的血色中,会依稀看见微茫的希望

1 条评论

konnyakuxzy · 2018年3月19日 8:28 下午

Orz!
太强了 Orz!
另外:
谁说我考场打的是贪心???






明明我打的是随机化+贪心
随机化跑不出答案再跑贪心
(但事实证明那俩瞎 jb 搞算法任意一个都能 A 掉考试的数据)
好吧我承认是数据水了
还是您强啊能写出正解 Orz
%%%

回复 konnyakuxzy 取消回复

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用 * 标注