放牧代码和思想
专注自然语言处理、机器学习算法
    愛しさ 優しさ すべて投げ出してもいい

POJ 1236 Network of Schools 题解《挑战程序设计竞赛》

目录

挑战程序设计竞赛第二版.jpg

POJ 1236 Network of Schools 

校园网:给定N所学校和网络,目标是分发软件其他学校都可收到,求①所需最少分发学校数;②若任选学校都能收到,最低新增边数。

4.3成为图论大师之路 

强连通分量分解

还是睡不着,再来一发吧。同一个强连通分量内的顶点合并为一个,在这个DAG上计算出度和入度。①其实是求入度为0的顶点数,②则是求0出度和0入度顶点数的较大者,因为要将这两类顶点连起来。

#include <iostream>
#include <cstring>
#include <vector>

using namespace std;
#define MAX_V 100 + 2

int V;                      // 顶点数
vector<int> G[MAX_V];       // 图的邻接表表示
vector<int> rG[MAX_V];      // 反向图
vector<int> vs;             // 后序遍历顺序的顶点列表
bool used[MAX_V];           // 访问标记
int cmp[MAX_V];             // 所属强连通分量的拓补序
int in[MAX_V], out[MAX_V];  // 入度、出度

void add_edge(const int &from, const int &to)
{
    G[from].push_back(to);
    rG[to].push_back(from);
}

void dfs(const int &v)
{
    used[v] = true;
    for (int i = 0; i < G[v].size(); ++i)
    {
        if (!used[G[v][i]])
            dfs(G[v][i]);
    }
    vs.push_back(v);
}

void rdfs(const int &v, const int &k)
{
    used[v] = true;
    cmp[v] = k;
    for (int i = 0; i < rG[v].size(); ++i)
    {
        if (!used[rG[v][i]])
            rdfs(rG[v][i], k);
    }
}

int scc()
{
    memset(used, 0, sizeof(used));
    vs.clear();
    for (int v = 0; v < V; ++v)
    {
        if (!used[v])
            dfs(v);
    }
    memset(used, 0, sizeof(used));
    int k = 0;
    for (int i = vs.size() - 1; i >= 0; --i)
    {
        if (!used[vs[i]])
            rdfs(vs[i], k++);
    }

    return k;
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
    scanf("%d", &V);
    for (int u = 0; u < V; ++u)
    {
        int v;
        while (scanf("%d", &v) && v)
        {
            add_edge(u, --v);
        }
    }

    int n = scc();
    if (n == 1)
    {
        puts("1\n0");       // 特殊情况
        return 0;
    }
    for (int u = 0; u < V; ++u)
    {
        for (int i = 0; i < G[u].size(); ++i)
        {
            int v = G[u][i];
            if (cmp[u] != cmp[v])               // 强连通分量算一个点
                ++out[cmp[u]], ++in[cmp[v]];
        }
    }

    int zero_in = 0, zero_out = 0;
    for (int i = 0; i < n; ++i)
    {
        if (in[i] == 0)
            ++zero_in;
        if (out[i] == 0)
            ++zero_out;
    }
    printf("%d\n", zero_in);
    printf("%d\n", max(zero_in, zero_out));    // 入度为0的点和出度为0的点建立连接
#ifndef ONLINE_JUDGE
    fclose(stdin);
#endif
    return 0;
}
16237875 hankcs 1236 Accepted 176K 16MS C++ 2038B 2016-10-28 15:41:17

知识共享许可协议 知识共享署名-非商业性使用-相同方式共享码农场 » POJ 1236 Network of Schools 题解《挑战程序设计竞赛》

评论 欢迎留言

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

我的作品

HanLP自然语言处理包《自然语言处理入门》