OJ 1234 校园网络
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
这道题有两问
第一问很简单,先tarjin缩一下点,然后找出所有入度为0的点,那么这些点是必须要副本的,其他的点一定可以有这些点到达,所以答案就是所有入度为0的点
第二问,有一个小结论,就是一个有向图我们只需要最多连max(入度为0的点的个数,初度为0的点的个数)条边,那么个图就可以成为强连通的,即从任意一个点可以到达另外所有点,但当只有一个强连通分量的时候要输出0而不是1
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
int x=0;int f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=1e4+10;
namespace zhangenming{
struct node{
int x,y,next;
}e[MAXN];
int linkk[MAXN],len=0,n;
inline void insert(int xx,int yy){
e[++len].y=yy;e[len].x=xx;e[len].next=linkk[xx];linkk[xx]=len;
}
void init(){
n=read();
for(int i=1;i<=n;i++){
int xx=read();
while(xx){
insert(i,xx);
xx=read();
}
}
}
int vis[MAXN],stark[MAXN],ine[MAXN],cntt[MAXN]={},tot=0,top=0,cnt[MAXN]={},dfn[MAXN]={},low[MAXN],dfs_clock=0;
inline void tarjin(int st){
//cout<<st<<endl;
dfn[st]=low[st]=++dfs_clock;vis[st]=1;
stark[++top]=st;
for(int i=linkk[st];i;i=e[i].next){
if(!dfn[e[i].y]){
//cout<<e[i].y<<endl;
tarjin(e[i].y);
low[st]=min(low[st],low[e[i].y]);
}
else if(vis[e[i].y]) low[st]=min(low[st],dfn[e[i].y]);
}
if(low[st]==dfn[st]){
tot++;
int k;
do{
k=stark[top--];
ine[k]=tot;
vis[k]=0;
}while(k!=st);
}
}
void solve(){
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
if(!ine[i]) tarjin(i);
}
for(int i=1;i<=len;i++){
int xx=e[i].x;int yy=e[i].y;
if(ine[xx]==ine[yy]) continue;
cnt[ine[yy]]++;
cntt[ine[xx]]++;
}
int sum1=0;int sum2=0;
for(int i=1;i<=tot;i++){
if(!cnt[i]) sum1++;
if(!cntt[i]) sum2++;
}
cout<<sum1<<endl;
if(tot!=1) cout<<max(sum1,sum2)<<endl;
else cout<<0<<endl;
}
}
int main(){
using namespace zhangenming;
init();
solve();
return 0;
}

浙公网安备 33010602011771号