hdu1827 Summer Holiday(Tarjan缩点+贪心)

来源:互联网 发布:iphone6s怎么备份数据 编辑:程序博客网 时间:2024/05/19 05:04


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

题意:给你n个人m个关系,n个人分别有联系到他的最小花费,求联系到所有人的最小花费。


思路:根据缩点把强连通都缩成节点变成有向无环图后,入度为0的点即为需要单独联系的人。至于花费,用贪心求最小花费即可。我们知道每个强连通分量已经被染色,那么找出入度为0的节点后,遍历所有节点,颜色相同就求其最小值,最后累加。


#include <stdio.h>#include <algorithm>#include <stdlib.h>#include <string.h>#include <iostream>#include <stack>#include <vector>using namespace std;typedef long long LL;const int N = 100010;const int INF = 1e8;stack<int>S;int dfn[N], low[N], head[N], Belong[N], in[N], out[N], countt, time, n, m, pos;bool instack[N];struct Edge{    int to, next;}edge[N];void add(int u, int v){    edge[pos].to = v;    edge[pos].next = head[u];    head[u] = pos++;}void init(){    time = countt = pos = 0;    memset(in, 0, sizeof(in));    memset(out, 0, sizeof(out));    memset(dfn, 0, sizeof(dfn));    memset(low, 0, sizeof(low));    memset(head, -1, sizeof(head));    memset(instack, false, sizeof(instack));}void Tarjan(int u){    int v;    dfn[u] = low[u] = ++time;    instack[u] = true;    S.push(u);    for(int i = head[u]; i != -1; i = edge[i].next)    {        v = edge[i].to;        if(dfn[v] == 0)        {            Tarjan(v);            low[u] = min(low[u], low[v]);        }        else if(instack[v] == 1)        {            low[u] = min(low[u], dfn[v]);        }    }    if(dfn[u] == low[u])    {        countt ++;        do        {            v = S.top();            S.pop();            instack[v] = false;            Belong[v] = countt;        }while(u != v);    }}int main(){  //  freopen("in.txt", "r", stdin);    int u, v, mon[N];    while(~scanf("%d%d", &n, &m))    {        init();        for(int i = 1; i <= n; i++)        {            scanf("%d", &mon[i]);        }        for(int i = 1; i <= m; i++)        {            scanf("%d%d", &u, &v);            add(u, v);        }        //缩点        for(int i = 1; i <= n; i++)        {            if(dfn[i] == 0)                Tarjan(i);        }        for(int i = 1; i <= n; i++)        {            for(int k = head[i]; k != -1; k = edge[k].next)            {                int j = edge[k].to;                if(Belong[i] != Belong[j])                {                    out[Belong[i]]++;                    in[Belong[j]]++;                }            }        }        //找叶子和根度为0的数量        int ans = 0, num = 0;        for(int i = 1; i <= countt; i++)        {            if(in[i] == 0)            {                int cost = INF;                num++;                for(int j = 1; j <= n; j++)                {                    if(Belong[j] == i)                        cost = min(cost, mon[j]);                }                ans += cost;            }        }        printf("%d %d\n", num, ans);    }    return 0;}


0 0
原创粉丝点击