#10093. 「一本通 3.5 練習 1」網路協議
阿新 • • 發佈:2021-02-01
技術標籤:強連通
一些學校連線在一個計算機網路上。學校之間存在軟體支援協議。每個學校都有它應支援的學校名單(學校 支援學校 ,並不表示學校 一定支援學校 )。當某校獲得一個新軟體時,無論是直接得到還是網路得到,該校都應立即將這個軟體通過網路傳送給它應支援的學校。因此,一個新軟體若想讓所有連線在網路上的學校都能使用,只需將其提供給一些學校即可。
任務
請編一個程式,根據學校間支援協議(各個學校的支援名單),計算最少需要將一個新軟體直接提供給多少個學校,才能使軟體通過網路被傳送到所有學校;
如果允許在原有支援協議上新增新的支援關係。則總可以形成一個新的協議,使得此時只需將一個新軟體提供給任何一個學校,其他所有學校就都可以通過網路獲得該軟體。程式設計計算最少需要新增幾條新的支援關係。
第一行是一個正整數 ,表示與網路連線的學校總數。 隨後 行分別表示每個學校要支援的學校,即: 行表示第 號學校要支援的所有學校代號,最後 結束。
如果一個學校不支援任何其他學校,相應行則會有一個 。一行中若有多個數字,數字之間以一個空格分隔。
輸出格式
包含兩行,第一行是一個正整數,表示任務 a 的解,第二行也是一個正整數,表示任務 b 的解。
樣例
輸入
5
2 4 3 0
4 5 0
0
0
1 0
輸出
1
2
資料範圍與提示
這道題和受歡迎的牛還是有點像
sc是強連通塊的塊數
scc表示不同的強連通塊,sz表示強連通塊中的點數
入度為零的點就是需要提供軟體的點,任務一的解就是入度為0的點,支援關係就是不管是入度還是出度,任務二的解是選擇出度和入度中較大的點數,如果不是較大的點數,那麼會出現仍然有點未被連結的情況。
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stack>
#define mem(a,b) memset(a,b,sizeof(a))
const int N=202000;
typedef long long ll;
using namespace std;
struct node
{
int to,net;
} e[N];
int head[N],tot;
void add(int u,int v)
{
e[++tot].to=v;
e[tot] .net=head[u];
head[u]=tot;
}
int dfn[N],low[N],cnt,s[N],tp;
int scc[N],sc;
int sz[N],n,m,out[N],in[N];
void tarjan(int u)
{
low[u]=dfn[u]=++cnt;
s[++tp]=u;
for(int i=head[u];i;i=e[i].net)
{
int v=e[i].to;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(!scc[v])
low[u]=min(low[u],low[v]);
}
if(dfn[u]==low[u])
{
++sc;
while(s[tp]!=u)
{
scc[s[tp]]=sc;
sz[sc]++;
--tp;
}
scc[s[tp]]=sc,sz[sc]++,--tp;
}
}
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
int u,v;
while(~scanf("%d",&u)&&u)
add(i,u);
}
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].net)
{
int v=e[i].to;
if(scc[u]==scc[v]) continue;
out[scc[u]]++;
in[scc[v]]++;
}
}
int ans1=0,ans2=0;
for(int i=1; i<=sc; i++)
{
if(in[i]==0)
++ans1;
if(out[i]==0)
++ans2;
}
if(sc==1)
printf("1\n0\n");
else
printf("%d\n%d\n",ans1,max(ans1,ans2));
return 0;
}