学校の[USACO5.3]キャンパスネットワークネットワーク
タイトル説明
でも、コンピュータネットワークへのいくつかの学校。これらの学校は、契約を締結しています。各学校は、他のいくつかの学校の配布ソフトウェア(「学校を受ける」と呼ばれる)を提供します。でも配信リストAのBの学校であればリストは、AがB-学校の中では必ずしもないことに注意してください。
あなたが計算するプログラムを書きたい、合意によると、すべての学校は、新しいソフトウェアを使用するネットワークを作るために、新しい学校は、ソフトウェア(サブタスクA)のコピー数の最小値を受け入れる必要があります。さらに、我々はネットワーク内のすべての学校に配布されるすべての新しいソフトウェアを、送信するために学校を通じて決定したかったです。このタスクを達成するために、我々は新しいメンバーにリストを受け取るために学校を展開する必要があります。私たちの新しいソフトウェアを送信するために学校に関係なく作る拡張子の数を増やすために必要な最低限を計算し、それが残りのすべての学校(サブタスクのB)に達します。拡張子は、学校のリストを受け取り、学校で新メンバーの紹介です。
入力形式
入力ファイルの最初の行は、正の整数N、学校のネットワークの番号を含みます。最初のNは正の整数で識別される学校。
次に、各ラインは、リストを受信ラインN学校(配布リスト)を表し、行I + 1-iは、学校、学校の識別子を受信することを含みます。各リストには、0、0、空のリストだけで1つの表現で終わります。
出力フォーマット
あなたのプログラムは、出力ファイルの出力の2行は必要があります。
最初の行は、正の整数、サブタスク図の溶液を含むべきです。
第二行は非負の整数、B液サブタスク図を含むべきです。
この問題は、比較テンプレートTarjan収縮点の問題であるが、より重要な点は、強連結グラフになること、及び辺の数を高めるためにDAGを理解することである浸透度であり、ポイント数が0であります点の最大数。
コード:
#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=20010;
const int M=1000100;
const LL mod=100000000;
int dfn[N],low[N],tot,head[N],cnt,n,sta[N],top,fa[N],in[N],out[N],sum;
vector<int>R[N];
bool vis[N],ma[N][N];
struct Node{
int to,nex;
}edge[M];
void add(int p,int q){
edge[cnt].to=q;
edge[cnt].nex=head[p];
head[p]=cnt++;
}
void Tarjan(int p){
dfn[p]=low[p]=++tot;
if(!vis[p]) vis[p]=true,sta[++top]=p;
for(int i=head[p];~i;i=edge[i].nex){
int q=edge[i].to;
if(!dfn[q]){
Tarjan(q);
low[p]=min(low[p],low[q]);
}
else if(vis[q]) low[p]=min(low[p],dfn[q]);
}
if(dfn[p]==low[p]){
sum++;//总点数
fa[p]=p;
vis[p]=false;
while(sta[top]!=p){
vis[sta[top]]=false;
fa[sta[top]]=p;
top--;
}
top--;
}
}
int main(){
memset(head,-1,sizeof(head));
cin>>n;
for(int i=1;i<=n;i++){
int q;
while(1){
scanf("%d",&q);
if(q==0) break;
add(i,q);
R[i].push_back(q);
}
}
for(int i=1;i<=n;i++){
if(!dfn[i]) Tarjan(i);
}
for(int i=1;i<=n;i++){
for(int j=0;j<R[i].size();j++){
if(fa[i]!=fa[R[i][j]]&&!ma[fa[i]][fa[R[i][j]]]){
ma[fa[i]][fa[R[i][j]]]=true;
in[fa[R[i][j]]]++;
out[fa[i]]++;
}
}
}
int ans1=0,ans2=0;
for(int i=1;i<=n;i++){
if(fa[i]==i&&in[i]==0) ans1++;
if(fa[i]==i&&out[i]==0) ans2++;
}
if(sum==1) cout<<1<<endl<<0<<endl;
else cout<<ans1<<endl<<max(ans1,ans2)<<endl;
return 0;
}