[USACO5.3]校园网Network of Schools,洛谷之提高历练地,强连通分量

正题

      [USACO5.3]校园网Network of Schools

      第一问:求至少从多少个节点开始,可以遍历整个图。

      第二问:求至少加上多少条边,使得无论从哪个节点开始,都可以遍历整张图

      首先声明先缩环成点。

      第一问就是求入度为0的点即可,因为不是入度为0的话,那么肯定可以从另外一个点传递信息过来。

      第二问好像很烦,要求的是加上多少条边可以使图成环。

      那么很明显啊,如果成环那么每个点都有入度和出度。

      所以我们就想一想答案是不是入度为0或者出度为0的点数的最大值。

      好像是对的。。。

      怎么证明

      首先无视边的方向,它肯定是一棵树。

      如果入度比出度大,那么必定能从出度为0的点连边到入度为0的点。剩下的入度为0的点从其他不是入度为0的点随便连即可。

      反之则同理。

      所以跑一便缩点,用ans1记录入度为0的点数,ans2记录出度为0的点数,输出答案即可。

#include
#include
#include
#include
#include
using namespace std;

int n,x;
struct edge{
    int x,y,next;
}s[10010];
struct node{
    int dfn,low;
}op[110];
int first[110],where[110];
int len=0;
stack f;
int now=0;
bool tf[110];
vector T[110];
int fa[110];
int in[110],out[110];
int tot=0;

void ins(int x,int y){
    len++;
    s[len].x=x;s[len].y=y;s[len].next=first[x];first[x]=len;
}

int findpa(int x){
    if(fa[x]!=x) return fa[x]=findpa(fa[x]);
    return fa[x];
}

void Tarjan(int x){
    op[x].dfn=op[x].low=++now;
    tf[x]=true;f.push(x);
    for(int i=first[x];i!=0;i=s[i].next){
        int y=s[i].y;
        if(op[y].dfn==0){
            Tarjan(y);
            if(op[y].low=1;i--){
    	if(where[s[i].x]==where[s[i].y]) continue;
        in[where[s[i].y]]++;
        out[where[s[i].x]]++;
    }
    for(int i=1;i<=tot;i++){
    	    if(in[i]==0) ans1++;
	    if(out[i]==0) ans2++;
	}
    if(tot==1) printf("1\n0");//如果连通分块的数量为1,那么很明显不用连边
    else printf("%d\n%d",ans1,max(ans2,ans1));
    return 0;
}

       

你可能感兴趣的:([USACO5.3]校园网Network of Schools,洛谷之提高历练地,强连通分量)