POJ1236 图的一个连通性问题

问题的证明

Network of Schools(POJ 1236) A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a list of schools to which it distributes software (the “receiving schools”). Note that if B is in the distribution list of school A, then A does not necessarily appear in the list of school B
You are to write a program that computes the minimal number of schools that must receive a copy of the new software in order for the software to reach all schools in the network according to the agreement (Subtask A). As a further task, we want to ensure that by sending the copy of new software to an arbitrary school, this software will reach all schools in the network. To achieve this goal we may have to extend the lists of receivers by new members. Compute the minimal number of extensions that have to be made so that whatever school we send the new software to, it will reach all other schools (Subtask B). One extension means introducing one new member into the list of receivers of one school.

一些小小的证明

由题目,我们可以建立学校之间的一个有向图,我们可以知道,强连通分量之间的点是可以互相到达的。所以我们使用tarjan算法计算出所有的强连通分量。如果这个图就是一个强连通图,那么我们可以知道只要在一个学校放上软件就可以了。下面我们来看非强连通图的情况。
我们将强连通分量缩成一个点,那么这些点之间仍然有可能单向相连。但是绝不可能双向相连。
第一个问题:我们最少要在多少学校放软件。我们计算所有强连通分量的入度,如果一个强连通分量的入度为0,那么我们要在这个强连通分量内放置软件。而容易知道每一个入度大于0的强连通分量都会和一个入度为0的强连通分量弱连通。所以我们只要计算缩点后的图中所有入度为0的点即可。
第二个问题:我们需要加入多少边才能让这个图变成一个强连通图呢?
证明:在一个有向连通图当中,这个图为强连通图当且仅当所有的点的入度和出度都不为0
必要性:显然如果图G为强连通图,那么所有的点的入度和出度都不为0
充分性:我们可以证明一个更强的结论:此时的图中包含一个欧拉子图。
有向图当中欧拉图的定义为:对于所有的点存在deg+ (v) = deg-(v)
而此时,我们有所有点的入度和出度都大于1,则删去适当的点,一定会得到一个连接所有 结点

实现代码

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

const int MAXN = 105;

int dfn[MAXN],low[MAXN],n;
int grid[MAXN][MAXN],state[MAXN],cur,num;
int outdeg[MAXN],indeg[MAXN],belong[MAXN];
stack<int>S;

void init()
{
    cur = 1; num = 0;
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(state,0,sizeof(state));
    memset(grid,0,sizeof(grid));
    memset(indeg,0,sizeof(indeg));
    memset(outdeg,0,sizeof(outdeg));
    memset(belong,0,sizeof(belong));
}

void Dfs(int index,int time)
{
    dfn[index] = low[index] = time;
    state[index] = 1;
    S.push(index);
    int i;
    for(i=1;i<=n;i++){
        if(grid[index][i] == 1){
            if(!state[i]){
                Dfs(i,++cur);
                low[index] = min(low[index],low[i]);
            }
            else if(state[i] == 1)
                low[index] = min(low[index],low[i]);
        }
    }
    if(dfn[index] == low[index]){
        num++;
        int temp;
        while(1){
            temp = S.top();
            S.pop();
            //printf("%d ",temp);
            belong[temp] = num;
            state[temp] = 2;
            if(temp == index)break;
        }
    }
}

void Solve()
{
    int i,j,ans1=0,ans2=0;
    for(i=1;i<=n;i++){
        if(!state[i]){
            Dfs(i,cur);
        }
    }
    for(i=1;i<=n;i++){
        for(j=1;j<=n;j++){
            if(grid[i][j] == 1 && belong[i] != belong[j]){
                indeg[belong[j]]++;
                outdeg[belong[i]]++;
            }
        }
    }
    for(i=1;i<=num;i++){
        if(!indeg[i])ans1++;
        if(!outdeg[i])ans2++;
    }
    if(num == 1)printf("1\n0\n");
    else
        printf("%d\n%d\n",ans1,max(ans1,ans2));
    return;
}

int main()
{
    freopen("input","r",stdin);
    int i,temp;
    init();
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        while(1){
            scanf("%d",&temp);
            if(!temp)break;
            grid[i][temp] = 1;
        }
    }
    Solve();
}

你可能感兴趣的:(图算法)