1. 程式人生 > >【洛谷P2746】Network of Schools

【洛谷P2746】Network of Schools

一個 add tchar get else if oid bits else dfs

題目大意:給定一個 N 個點,M 條邊的有向圖,第一問求至少從多少個點出發才能遍歷整個有向圖,第二問求至少在這個有向圖的基礎上加多少條邊才能使得該無向圖強連通。

題解:先進行 Tarjan 縮點,得到一個 DAG。對於這個 DAG 來說,第一問顯然是入度為 0 點的個數。第二問中的每條新邊均應該是在出度為 0 點和入度為 0 點之間添加,因此答案是入度為 0 的點的個數和出度為 0 點的個數的最大值。另外,若只有一個強聯通分量的話,需要特判。

代碼如下

#include <bits/stdc++.h>
using namespace std;
const int maxv=110;
const int maxe=1e4+10;

inline int read(){
    int x=0,f=1;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
    do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
    return f*x;
}

struct node{
    int nxt,to;
}e[maxe];
int tot=1,head[maxv];
inline void add_edge(int from,int to){
    e[++tot]=node{head[from],to},head[from]=tot;
}

int n;
int dfs_clk,low[maxv],dfn[maxv],stk[maxv],top,in[maxv];
int scc,cor[maxv];
vector<int> G[maxv];
int indeg[maxv],outdeg[maxv],ans1,ans2;

void tarjan(int u){
    dfn[u]=low[u]=++dfs_clk;
    stk[++top]=u,in[u]=1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(!dfn[v])tarjan(v),low[u]=min(low[u],low[v]);
        else if(in[v])low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        ++scc;int v;
        do{
            v=stk[top--],in[v]=0;
            cor[v]=scc;
        }while(u!=v);
    }
}

void read_and_parse(){
    n=read();
    for(int i=1,to;i<=n;i++)while(to=read())add_edge(i,to);
}

void solve(){
    for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
    for(int u=1;u<=n;u++)
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(cor[v]==cor[u])continue;
            G[cor[u]].push_back(cor[v]),++indeg[cor[v]],++outdeg[cor[u]];
        }
    for(int i=1;i<=scc;i++){
        if(!indeg[i])++ans1;
        if(!outdeg[i])++ans2;
    }
    ans2=scc==1?0:max(ans2,ans1);
    printf("%d\n%d\n",ans1,ans2);
}

int main(){
    read_and_parse();
    solve();
    return 0;
}

【洛谷P2746】Network of Schools