poj1236 强连通分量——缩点

来源:互联网 发布:知乎 阑夕 老司机 编辑:程序博客网 时间:2024/05/22 08:26

【题意】

N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。

【题解】

找强连通分量,缩点。记f[i]为缩完点后的新图中各点入度,g[i]为出度,ans1为f[i]==0的点的数目,ans2为g[i]==0的点的数目则第一问为ans1,第二问则为max{ans1,ans2}。

至于第二问的解释,我的想法是对于得到的DAG图,考虑其中的出度为0的点和入度为0的点组成的点集V,将这些点相连,最多这需要max{ans1,ans2}条边,就能使整个图成为强连通分量。

但是请注意,大家可能都没发现,这个结论的前提是DAG图是连通的情况下才成立。如果DAG图有多个连通分量,则还要考虑将多个连通分量合并的所需代价。幸运的是,这道题保证了只有一个连通分量。(题目第一句话所说)

#include <iostream>#include <algorithm>using namespace std;const int maxn=105;const int maxe=105*105;struct edge{       int x,y,next;}e[maxe];int g[maxn],dfn[maxn],low[maxn],v[maxn],f[maxn],s[maxn],b[maxn],h[maxn];int n,tot=0,cnt=0,ans=0,times=0,t=0,ans2;void ins(int x,int y){     e[++tot].x=x;e[tot].y=y;     e[tot].next=h[x];h[x]=tot;}void tarjan(int x){     int y,i;     times++;t++;     dfn[x]=low[x]=times;     v[x]=1;s[t]=x;     for (i=h[x];i;i=e[i].next)     {         y=e[i].y;         if (v[y]==0)         {            tarjan(y);            low[x]=min(low[x],low[y]);         }         if (v[y]==1)            low[x]=min(low[x],dfn[y]);     }     if (dfn[x]==low[x])     {        cnt++;        do        {              y=s[t--];              b[y]=cnt;v[y]=2;        }while (y!=x);     }}         int main(){    freopen("pin.txt","r",stdin);    freopen("pou.txt","w",stdout);    int i,j;    cin >> n;    for (i=1;i<=n;i++)    {        cin >> j;        while (j)        {              ins(i,j);              cin >> j;        }    }    for (i=1;i<=n;i++)        if (v[i]==0)           tarjan(i);    if (cnt==1)    {             cout << 1 << endl << 0 << endl;             return 0;    }    for (i=1;i<=tot;i++)        if (b[e[i].x]!=b[e[i].y])        {           f[b[e[i].x]]++;           g[b[e[i].y]]++;        }    ans=0;    for (i=1;i<=cnt;i++)        if (g[i]==0) ans++;    cout << ans << endl;    ans2=0;    for (i=1;i<=cnt;i++)        if (f[i]==0) ans2++;    cout << max(ans,ans2)<< endl;}


原创粉丝点击