• 杭电1827--Summer Holiday(SCC + 缩点)


    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1827

    第二道强连通分量题目, 对于SCC也有了一定的认识, 所以想在这里总结一下;有向非强连通图的极大强连通子图叫做强连通分量 (SCC), 所有强连通分量在原图中组成一个DAG(每个强连通分量看作一个点)。TarJan() 算法利用Dfs找强连通分量, 我们可以把Dfs搜索过程看作是一个整体,个人感觉分步模拟并不是很好理解。 

    Low[]: 时间戳;(树根)。 

    dfn[]; 记录搜索当前节点的时间。 

    当搜索到强连通分量时, 让根节点及其以上节点弹出栈。(instack[u] = 0)。可以进行操作是记录SCC个数 && 缩点 && 记录SCC中结点的个数。

    本题题意是在一个有向关系图中, 花最少的话费, 把消息通知到所有人。
    看SCC入度 V, V!= 0 不需花费, V == 0, 取花费最少节点, 注意操作一致性。

    #include <stack>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int INF = 0x3f3f3f3f;
    int dfn[1001], low[1001], instack[1001], sccf[1001], Rdu[1001], Cost[1001], cnt_SCC, vis_num, total, n, m;
    struct Edge
    {
        int from, to, next;
    } edge[2010];
    int cnt, head[1001];
    void Add(int a, int b)
    {
        Edge E = {a, b, head[a]};
        edge[cnt] = E;
        head[a] = cnt++;
    }
    stack<int> S;
    void TarJan(int x)
    {
        int j;
        dfn[x] = low[x] = ++vis_num;
        instack[x] = 1;
        S.push(x);
        for(int  i = head[x]; i != -1; i = edge[i].next)
        {
            int u = edge[i].to;
            if(dfn[u] == -1)
            {
                TarJan(u);
                if(low[x] > low[u])
                    low[x] = low[u];
            }
            else if(instack[u] && low[x] > dfn[u])
                low[x] = dfn[u]; 
        }
        if(low[x] == dfn[x])
        {
            cnt_SCC++;
            do{
                j = S.top();
                sccf[j] = cnt_SCC;
                S.pop(); 
                instack[j] = 0;
            }
            while(j != x);
        }
    }
    void Deal()   //确定结果; 
    {
        for(int i = 1; i <= n; i++)
        {
            for(int k = head[i]; k != -1; k = edge[k].next)
            {
                int u = edge[k].to;
                if(sccf[u] != sccf[i])
                    Rdu[sccf[u]]++;
            }
        }
        int ReSult = 0;
        for(int i = 1; i <= cnt_SCC; i++)
        {
            if(!Rdu[i])
            {
                ReSult++;
                int minn = INF; 
                for(int j = 1; j <= n; j++)
                { 
                    if(sccf[j] == i)
                        minn = min(minn, Cost[j]);
                }
                total += minn;    
            }
        }
        printf("%d %d
    ", ReSult, total);
    }
    void SolVe()
    {
        vis_num = cnt_SCC = total = 0;
        for(int i = 1; i <= n; i++)
            if(dfn[i] == -1) 
                TarJan(i);
    //    printf("%d
    ", cnt_SCC);
    } 
    void GetMap()
    {
        memset(Rdu, 0, sizeof(Rdu));
        memset(low, 0, sizeof(low)); 
        memset(dfn, -1, sizeof(dfn));
        memset(head, -1, sizeof(head));
        memset(instack, 0, sizeof(instack));
        
        cnt = 0;
        for(int i = 1; i <= m; i++)
        {
            int a, b;
            scanf("%d %d", &a, &b);
            Add(a, b);
        }
    }
    int main()
    {
        while(~scanf("%d %d", &n, &m))
        {
            for(int i = 1; i <= n; i++)
                scanf("%d", &Cost[i]);
            
            GetMap();
            SolVe();
            Deal();
        }
        return 0;
    }
  • 相关阅读:
    socket是什么
    0,1,2 代表标准输入、标准输出、标准错误
    认识程序的执行:从高级语言到二进制,以java为例
    97 条 Linux 运维工程师常用命令总结[转]
    rsync 参数配置说明[转]
    shell 脚本学习之内部变量
    ansible 入门学习(一)
    python 管理多版本之pyenv
    CentOS6 克 隆
    yum 本地仓库搭建
  • 原文地址:https://www.cnblogs.com/soTired/p/4813210.html
Copyright © 2020-2023  润新知