1. 程式人生 > >洛谷P2746 校園網Network of Schools

洛谷P2746 校園網Network of Schools

names urn space push class 發揮 max can spa

題目描述

一些學校連入一個電腦網絡。那些學校已訂立了協議:每個學校都會給其它的一些學校分發軟件(稱作“接受學校”)。註意即使 \(B\)\(A\) 學校的分發列表中, \(A\) 也不一定在 \(B\) 學校的列表中。

你要寫一個程序計算,根據協議,為了讓網絡中所有的學校都用上新軟件,必須接受新軟件副本的最少學校數目(子任務 \(A\))。更進一步,我們想要確定通過給任意一個學校發送新軟件,這個軟件就會分發到網絡中的所有學校。為了完成這個任務,我們可能必須擴展接收學校列表,使其加入新成員。計算最少需要增加幾個擴展,使得不論我們給哪個學校發送新軟件,它都會到達其余所有的學校(子任務 \(B\)

)。一個擴展就是在一個學校的接收學校列表中引入一個新成員。

輸入輸出格式

輸入格式:

輸入文件的第一行包括一個整數 \(N\):網絡中的學校數目(\(2 <= N <= 100\))。學校用前 \(N\) 個正整數標識。

接下來 \(N\) 行中每行都表示一個接收學校列表(分發列表)。第 \(i+1\) 行包括學校 \(i\) 的接收學校的標識符。每個列表用 \(0\) 結束。空列表只用一個 \(0\) 表示。

輸出格式:

你的程序應該在輸出文件中輸出兩行。

第一行應該包括一個正整數:子任務 \(A\) 的解。

第二行應該包括子任務 \(B\) 的解。

輸入輸出樣例

輸入樣例#1:

5
2 4 3 0
4 5 0
0
0
1 0

輸出樣例#1:

1
2

說明

題目翻譯來自NOCOW。

USACO Training Section 5.3

思路:對於子任務A,明顯,如果沒有連向某個點的邊,肯定就要讓這個點加入計劃,否則無法使整張圖組成一個強連通分量,因此,子任務A的答案即為入度為0的點的個數,對於子任務B,考慮我們用出度為0的點向入度為0的點連邊,使整張圖強連通,一個漏下也不滿足條件,所以子任務B的答案為出度為0的點的個數和入度為0的點的個數的最大值。然後如果幾個點已經構成了一個強連通分量,那麽它們在整張圖中只發揮一個點的作用,所以可以考慮縮點,然後記錄縮點之後的入度和出度,輸出兩個答案即可。

代碼:

#include<cstdio>
#include<iostream>
#include<stack>
#define maxn 101
using namespace std;
int n,num,js,cnt,rd[maxn],cd[maxn],head[maxn],dfn[maxn],low[maxn],bel[maxn],size[maxn];
int x1,x2;
bool vis[maxn];
struct node {
  int v,nxt;
}e[10001];
inline void ct(int u, int v) {
  e[++num].v=v;
  e[num].nxt=head[u];
  head[u]=num;
}
inline int maxx(int a, int b) {return a>=b?a:b;}
stack<int>q;
void tarjan(int u) {
  dfn[u]=low[u]=++cnt;
  q.push(u),vis[u]=1;
  for(int i=head[u];i;i=e[i].nxt) {
    int v=e[i].v;
    if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
    else if(vis[v]) low[u]=min(low[u],dfn[v]);
  }
  if(dfn[u]==low[u]) {
    int x=-1;js++;
    while(x!=u) {
      x=q.top(),q.pop();
      bel[x]=js,size[js]++;
      vis[x]=0;
    }
  }
}
int main() {
  scanf("%d",&n);
  for(int i=1,x;i<=n;++i) {
    while(scanf("%d",&x)==1) {
      if(!x) break;
      ct(i,x);
    }
  }
  for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
  for(int k=1;k<=n;++k) {
    for(int i=head[k];i;i=e[i].nxt) {
      int v=e[i].v;
      if(bel[k]!=bel[v]) ++cd[bel[k]],++rd[bel[v]];
    }
  }
  for(int i=1;i<=js;++i) {
    if(!cd[i]) ++x1;
    if(!rd[i]) ++x2;
  }
  printf("%d\n%d\n",x2,max(x1,x2));
  return 0;
}

洛谷P2746 校園網Network of Schools