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;
}
原文地址:https://www.cnblogs.com/DF-yimeng/p/9619354.html