• Tarjan缩点求入度为零的点的个数问题


    Description:

      一堆人需要联系,但如果x 可以联系 y,你联系了x就不用联系y了,你联系一个人都会有固定的花费,问你最小联系多少人,和最小花费

    Solution:
      Tarjan缩点,求出缩点的入度,如果为0则代表这个缩点需要联系一次,缩点的时候维护好根点到达该缩点的最小值即可

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    const int maxn = 1e4 + 1e2;
    const int maxm = 2e4 + 2e2;
    
    //tarjan
    int dfn[maxn],low[maxn],tot;
    
    //edge
    struct node{
        int to,pre;
    }e[maxn];
    int id[maxn],cnt;
    
    //color
    int col[maxn],cid;
    int in[maxn];
    //stack
    int stk[maxn],siz;
    bool instk[maxn];
    
    //Pdata
    int cost[maxn];
    int mincost[maxn];
    void init()
    {
        memset(id,-1,sizeof(id));
        cnt = tot = cid = siz = 0;
        memset(dfn,0,sizeof(dfn));
        memset(mincost,-1,sizeof(mincost));
        memset(instk,0,sizeof(instk));
        memset(stk,0,sizeof(stk));
        memset(in,0,sizeof(in));
    }
    void add(int from,int to)
    {
        e[cnt].to = to;
        e[cnt].pre = id[from];
        id[from] = cnt++;
    }
    void tarjan(int now)
    {
        dfn[now] = low[now] = ++tot;
        stk[siz++] = now;
        instk[now] = true;
    
        for(int i = id[now];~i;i = e[i].pre)
        {
            int to = e[i].to;
            if(!dfn[to])
            {
                tarjan(to);
                low[now] = min(low[now],low[to]);
            }
            else if(instk[to])
            {
                low[now] = min(low[now],dfn[to]);
            }
        }
    
        if(dfn[now] == low[now])
        {
            ++cid;
            while(siz > 0 && stk[siz] != now)
            {
                --siz;
                instk[stk[siz]] = false;
                col[stk[siz]] = cid;
                if(mincost[cid] == -1)mincost[cid] = cost[stk[siz]];
                else mincost[cid] = min(mincost[cid],cost[stk[siz]]);
            }
        }
    }
    int main()
    {
        int n,m;
        while(~scanf("%d%d",&n,&m))
        {
            init();
            for(int i = 1;i <= n;++i)
                scanf("%d",&cost[i]);
            int from,to;
            for(int i = 1;i <= m;++i)
            {
                scanf("%d%d",&from,&to);
                add(from,to);
            }
            for(int i = 1;i <= n;++i)
            {
                if(!dfn[i])tarjan(i);
            }
            for(int now = 1;now <= n;++now)
            {
                for(int i = id[now];~i;i = e[i].pre)
                {
                    int to = e[i].to;
                    if(col[now] != col[to])
                    {
                        ++in[col[to]];
                    }
                }
            }
            int rescnt = 0,ressum = 0;
            for(int i = 1;i <= cid;++i)
            {
                if(!in[i])
                {
                    ressum += mincost[i];
                    ++rescnt;
                }
            }
    
            printf("%d %d
    ",rescnt,ressum);
        }
        return 0;
    }
    
  • 相关阅读:
    Leetcode刷题记录--39. 组合总和
    Leetcode刷题记录--31. 下一个排列
    Leetcode刷题记录--22. 括号生成(回溯)
    Leetcode刷题记录--17. 电话号码的字母组合(回溯)
    分布式学习之--6.824MITLab1记录
    总结javascript处理异步的方法
    引用、浅拷贝及深拷贝 到 Map、Set(含对象assign、freeze方法、WeakMap、WeakSet及数组map、reduce等等方法)
    Vue之富文本tinymce爬坑录
    iOS 13 正式发布,来看看有哪些 API 变动
    Vuex,从入门到...
  • 原文地址:https://www.cnblogs.com/DF-yimeng/p/9619354.html
Copyright © 2020-2023  润新知