HDU 1827


HDU - 1827
Time Limit: 1000MS Memory Limit: 32768KB 64bit IO Format: %I64d & %I64u


To see a World in a Grain of Sand
And a Heaven in a Wild Flower,
Hold Infinity in the palm of your hand
And Eternity in an hour.
                  ―― William Blake

听说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
 

Hint

Source

HDOJ 2007 Summer Exercise(3)- Hold by Wiskey


中文题,题意不解释了。
思路: 怎样找到最少的联系人数和最小的花费。其实就是求强连通分量 + 缩点。判断一下每个强连通分量的入度是否为0,如果为0的话,说明这个分量的所有人没有人联系到他们,因此联系这个强连通分量中花费最小的点即可。
AC代码: 上模板 23333
/*~~~~~~~~~~~~~~~
HDU 1827
   by mowenwen
     2015.8.28
~~~~~~~~~~~~~~~*/
#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;  //这里写错,wa了快20发,555555
			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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值