hdu--1827

来源:互联网 发布:轻声密语知乎 编辑:程序博客网 时间:2024/05/30 18:30

Summer Holiday

Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2333    Accepted Submission(s): 1092


Problem Description
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 162 2 2 2 2 2 2 2 2 2 2 2 1 33 22 13 42 43 55 44 66 47 47 127 88 78 910 911 10
 

Sample Output
3 6
 
题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1827

考查点:强连通分量+缩点

解体思路: 一个强联通分量里选择任何一个人..都可以把这个强联通分量里的人通知到..并且可以把从这个强联通分量所能达的所有强联通分量覆盖到..先用tarjan求出所有的强联通分量...再算出每个强联通分量里所需花费最少的人为多少..最后找出入度为0的强联通分量..其个数就是第一个答案..它们的花费之和就是第二个答案..

代码如下:


#include<stdio.h>#include<string.h>#include<stack>#include<algorithm>using namespace std;struct stu{int f,t,ne;};stack<int>S;int sco[1010];int scc_on[1010];stu edge[2010];int head[1010];int dfn[1010];int low[1010];int num,s_clock,scc,n;int cost[1010];int instack[1010];int C[1010];void inin(){num=0;memset(head,-1,sizeof(head));}void add(int a,int b){  stu E={a,b,head[a]};  edge[num]=E;  head[a]=num++;}void tarjan(int u){int v;dfn[u]=low[u]=++s_clock;instack[u]=1;S.push(u);for(int i=head[u];i!=-1;i=edge[i].ne){v=edge[i].t;if(!dfn[v]){tarjan(v);low[u]=min(low[u],low[v]);}else if(instack[v])low[u]=min(low[u],dfn[v]);}if(low[u]==dfn[u]){scc++;do{v=S.top();S.pop();instack[v]=0;scc_on[v]=scc;}while(u!=v);}}void find(int m){memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(instack,0,sizeof(instack));s_clock=scc=0;while(!S.empty()){S.pop();}for(int i=1;i<=n;i++){if(!dfn[i])tarjan(i);}}int main(){int a,b,m;while(scanf("%d%d",&n,&m)!=EOF){inin();for(int i=1;i<=n;i++)scanf("%d",&cost[i]);for(int i=1;i<=m;i++){scanf("%d%d",&a,&b);;add(a,b);}find(1);memset(C,0x3f,sizeof(C));    for(int i=1;i<=n;i++)C[scc_on[i]]=min(C[scc_on[i]],cost[i]);//求出每一个强连通分量的最小花费for(int i=0;i<num;i++){if(scc_on[edge[i].f]!=scc_on[edge[i].t])//找出相关联的强连通分量C[scc_on[edge[i].t]]=0;}int sum1,sum2;sum1=sum2=0;for(int i=1;i<=scc;i++){if(C[i])//统计花费{sum2+=C[i];sum1++;}}printf("%d %d\n",sum1,sum2);}return 0;}


0 0
原创粉丝点击