HDU-1827

听说lcy帮大家预定了新马泰7日游,Wiskey真是高兴的夜不能寐啊,他想着得快点把这消息告诉大家,虽然他手上有所有人的联系方式,但是一个一个联系过去实在太耗时间和电话费了。他知道其他人也有一些别人的联系方式,这样他可以通知其他人,再让其他人帮忙通知一下别人。你能帮Wiskey计算出至少要通知多少人,至少得花多少电话费就能让所有人都被通知到吗?

Input多组测试数组,以EOF结束。
第一行两个整数N和M(1<=N<=1000, 1<=M<=2000),表示人数和联系对数。
接下一行有N个整数,表示Wiskey联系第i个人的电话费用。
接着有M行,每行有两个整数X,Y,表示X能联系到Y,但是不表示Y也能联系X。
Output输出最小联系人数和最小花费。
每个CASE输出答案一行。
Sample Input

12 16
2 2 2 2 2 2 2 2 2 2 2 2 
1 3
3 2
2 1
3 4
2 4
3 5
5 4
4 6
6 4
7 4
7 12
7 8
8 7
8 9
10 9
11 10

Sample Output

3 6

思路:tarjan缩点后找每个分量中最便宜的加起来,入度为0的点必买.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define inf 0x7fffffff
#define maxn 1000+10
#define maxm 2000+10
struct Edge
{
  int next,v;
}edge[maxm];
int n,m,index,top,tot,scc;
int head[maxn],Stack[maxn],dfn[maxn],low[maxn],belong[maxn],cost[maxn];
int indegree[maxn], outdegree[maxn];
bool instack[maxn];
int Max(int a,int b)
{
  return a > b? a: b;
}
void init()
{
    memset(head, -1, sizeof(head));
    memset(instack, false, sizeof(instack));
    memset(dfn, -1, sizeof(dfn));
    memset(low, 0, sizeof(low));
    memset(indegree, 0, sizeof(indegree));
    memset(outdegree, 0, sizeof(outdegree));
    memset(belong, 0,sizeof(belong));
    tot = 0;
    index = 0;
    top = 0;
    scc = 0;
}
void addedge(int u,int v)
{
    edge[tot].next = head[u];
    edge[tot].v = v;
    head[u] = tot ++;
}
void tarjan(int u)
{
    int v;
    dfn[u] = low[u] = ++index;
    Stack[top ++] = u;
    instack[u] = true;
    for(int i = head[u];i != -1;i = edge[i].next)
    {
        v = edge[i].v;
        if(dfn[v] == -1)
        {
          tarjan(v);
          if(low[v] < low[u])
           low[u] = low[v];
        }
        else
        {
          if(instack[v] && dfn[v] < low[u])
          {
            low[u] = dfn[v];
          }
        }

    }
    if(dfn[u] == low[u])
    {
        scc ++;
        int j;
        do
        {
            j = Stack[--top];
            instack[j] = false;  
            belong[j] = scc;
        }
        while(j != u);
    }
}
void solve()
{
    for(int i = 1;i <= n;i ++)
    {
      if(dfn[i] == -1)
      tarjan(i);
    }
}
int main()
{
    while(scanf("%d%d", &n, &m) != EOF)
    {
      init();
      for(int i = 1;i <= n;i ++)
        scanf("%d", &cost[i]);
      while(m --)
      {
          int a, b;
          scanf("%d%d", &a, &b);
          addedge(a, b);
      }
      solve();
      for(int i = 1;i <= n;i ++)
      {
        for(int j = head[i];j != -1;j = edge[j].next)
        {
            int u = i;
            int v = edge[j].v;
            if(belong[u] != belong[v])
            {
              indegree[belong[v]] ++;
            }
        }
      }
      int ans = 0,cnt = 0;
      int mincost;
      for(int i = 1;i <= scc;i ++)
      {
        mincost = inf;
        if(indegree[i] == 0)
        {
            cnt ++;
            for(int j = 1;j <= n;j ++)
            {
              if(belong[j] == i)
              {
                mincost = min(mincost, cost[j]);
              }
            }
            ans += mincost;
        }
      }

     printf("%d %d\n",cnt,ans);
    }
    return 0;
}

 

posted @ 2020-07-24 17:59  remarkableboy  阅读(118)  评论(0编辑  收藏  举报