poj1236 强连通分量——缩点

【题意】

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;
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值