nyoj 120 校园网络(求添加多少条边使整个图强连通)

校园网络

时间限制:3000 ms  |  内存限制:65535 KB
难度:5
 
描述

南阳理工学院共有M个系,分别编号1~M,其中各个系之间达成有一定的协议,如果某系有新软件可用时,该系将允许一些其它的系复制并使用该软件。但该允许关系是单向的,即:A系允许B系使用A的软件时,B未必一定允许A使用B的软件。

现在,请你写一个程序,根据各个系之间达成的协议情况,计算出最少需要添加多少个两系之间的这种允许关系,才能使任何一个系有软件使用的时候,其它所有系也都有软件可用。

 
输入
第一行输入一个整数T,表示测试数据的组数(T<10)
每组测试数据的第一行是一个整数M,表示共有M个系(2<=M<=100)。
随后的M行,每行都有一些整数,其中的第i行表示系i允许这几个系复制并使用系i的软件。每行结尾都是一个0,表示本行输入结束。如果某个系不允许其它任何系使用该系软件,则本行只有一个0.
输出
对于每组测试数据,输出最少需要添加的这种允许关系的个数。
样例输入
1
5
2 4 3 0
4 5 0
0
0
1 0
样例输出
2

题解:求出所有的scc并缩点后,记录每个scc的入度和出度,取入度为0的数和出度等于0的数的 的最大值即为要添加的边
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include<stdio.h>
#include<string.h>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<cstdio>
#include<string>
#include<math.h>
#include<algorithm>
#define LL long long
#define PI atan(1.0)*4
#define DD double
#define MAX 20000
#define mod 100
#define dian 1.000000011
#define INF 0x3f3f3f
using namespace std;
int head[MAX],ans;
int low[MAX],dfn[MAX];
int instack[MAX];
int n,m;
int in[MAX],out[MAX];
int scccnt,dclock,sccno[MAX];
stack<int>s;
vector<int>newmap[MAX];
struct node
{
    int u,v,next;
}edge[MAX];
void add(int u,int v)
{
    edge[ans].u=u;
    edge[ans].v=v;
    edge[ans].next=head[u];
    head[u]=ans++;
}
void init()
{
    ans=0;
    memset(head,-1,sizeof(head));
}
void tarjan(int u)
{
    int v,i,j;
    s.push(u);
    instack[u]=1;
    low[u]=dfn[u]=++dclock;
    for(i=head[u];i!=-1;i=edge[i].next)
    {
        v=edge[i].v;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(instack[v])
        low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        scccnt++;
        while(1)
        {
            v=s.top();
            s.pop();
            instack[v]=0;
            sccno[v]=scccnt;
            if(v==u)
                break;
        }
    }
}
void find(int l,int r)
{
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    memset(instack,0,sizeof(instack));
    memset(sccno,0,sizeof(sccno));
    dclock=scccnt=0;
    for(int i=l;i<=r;i++)
    {
        if(!dfn[i])
            tarjan(i);
    }
}
void suodian()
{
    int i;
    for(i=1;i<=scccnt;i++)
    {
        newmap[i].clear();
        in[i]=0;out[i]=0;
    }
    for(i=0;i<ans;i++)
    {
        int u=sccno[edge[i].u];
        int v=sccno[edge[i].v];
        if(u!=v)
        {
            newmap[u].push_back(v);
            in[v]++;
            out[u]++;
        }
    }
}
void solve()
{
    int i,j;
    if(scccnt==1)
    {
        printf("0\n");
        return ;
    }
    else
    {
        int minn=0;
        int maxx=0;
        for(i=1;i<=scccnt;i++)
        {
            if(!in[i])
                minn++;
            if(!out[i])
                maxx++;
        }
        printf("%d\n",max(minn,maxx));
    }
}
int main()
{
    int j,i,sum,l,t,k;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&m);
        init();
        for(i=1;i<=m;i++)
        {
            while(scanf("%d",&n),n)
                add(i,n);
        }
        find(1,m);
        suodian();
        solve();
    }
    return 0;
}

  

posted @   非我非非我  阅读(222)  评论(0编辑  收藏  举报
编辑推荐:
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
阅读排行:
· C# 13 中的新增功能实操
· Ollama本地部署大模型总结
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(4)
· langchain0.3教程:从0到1打造一个智能聊天机器人
· 用一种新的分类方法梳理设计模式的脉络
历史上的今天:
2015-03-31 nyoj 14 会场安排问题
点击右上角即可分享
微信分享提示