HDOJ-1827-Summer Holiday 解题报告

       强连通分量题。中文题意不说了。


       我的解题思路:这是一个有向图,将这个有向图缩点成强连通分量图之后,最少需要联系的人数就是这个强连通分量图中入度为0的强连通分量的个数。每个强连通分量的最小花费就是这个强连通分量里面花费最少的点。


       我的解题代码:强连通分量Tarjan算法+缩点

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;

#define N 1002
#define INF 0x3f3f3f3f

vector <int> e[N];
int dfn[N], low[N];
int vis[N];             //0代表未访问,1代表已访问,2代表在栈中
int belong[N];          //存储每个顶点属于哪个强连通分量
int stack[N], stop;     //手写栈
int timer;              //访问时间戳
int sccn;               //强连通分量的数量
int dist[N];            //每个点的花费
int cost[N];            //每个强连通的最小花费
int n, m;

void InitRead();

void DataProcess();

void Tarjan(int x);

int main()
{
    while (~scanf("%d %d", &n, &m))
    {
        InitRead();
        DataProcess();
    }
    return 0;
}

void InitRead()
{
    timer = stop = sccn = 0;
    memset(vis, 0, sizeof(vis));
    for (int i=1; i<=n; ++i)
    {
        e[i].clear();
        scanf("%d", &dist[i]);
    }
    int a, b;
    for (int i=0; i<m; ++i)
    {
        scanf("%d %d", &a, &b);
        e[a].push_back(b);
    }
    return;
}

void DataProcess()
{
    int indeg[N] = {0};     //存储强连通分量的入度
    for (int i=1; i<=n; ++i)
    {
        if (!vis[i])
        {
            Tarjan(i);
        }
    }
    for (int i=1; i<=n; ++i)
    {
        int size = e[i].size();
        for (int j=0; j<size; ++j)
        {
            if (belong[i] != belong[e[i][j]])
            {
                indeg[belong[e[i][j]]]++;
            }
        }
    }
    int ansn = 0, anscost = 0;
    for (int i=1; i<=sccn; ++i)
    {
        if (indeg[i] == 0) 
        {
            ansn++;
            anscost += cost[i];
        }
    }
    printf("%d %d\n", ansn, anscost);
    return;
}

void Tarjan(int x)
{
    int y;
    dfn[x] = low[x] = ++timer;
    stack[stop++] = x;
    vis[x] = 2;
    int size = e[x].size();
    for (int i=0; i<size; ++i)
    {
        y = e[x][i];
        if (!vis[u])
        {
            Tarjan(y);
            low[x] = min(low[x], low[y]);
        }
        else if (vis[e[x][i]] == 2)
        {
            low[x] = min(low[x], dfn[y]);
        }
    }
    if (dfn[x] == low[x])
    {
        sccn++;
        int mincost = INF;
        do 
        {
            y = stack[--stop];
            vis[y] = 1;
            belong[y] = sccn;
            mincost = min(mincost, dist[y]);
        } while (x != y);
        cost[sccn] = mincost;
    }
    return;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值