HDU 1827 Summer Holiday (Tarjan)
Summer Holiday
Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1147 Accepted Submission(s): 503
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计算出至少要通知多少人,至少得花多少电话费就能让所有人都被通知到吗?
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。
第一行两个整数N和M(1<=N<=1000, 1<=M<=2000),表示人数和联系对数。
接下一行有N个整数,表示Wiskey联系第i个人的电话费用。
接着有M行,每行有两个整数X,Y,表示X能联系到Y,但是不表示Y也能联系X。
Output
输出最小联系人数和最小花费。
每个CASE输出答案一行。
每个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
Author
威士忌
Source
Recommend
威士忌
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int VM=1010; const int EM=2010; const int INF=0x3f3f3f3f; struct Edge{ int to,nxt; }edge[EM<<1]; int n,m,cnt,head[VM],cost[VM],tcost[VM]; int dep,top,atype; int dfn[VM],low[VM],vis[VM],stack[VM],belong[VM],indeg[VM],outdeg[VM]; void addedge(int cu,int cv){ edge[cnt].to=cv; edge[cnt].nxt=head[cu]; head[cu]=cnt++; } void Tarjan(int u){ dfn[u]=low[u]=++dep; stack[top++]=u; vis[u]=1; for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(!dfn[v]){ Tarjan(v); low[u]=min(low[u],low[v]); }else if(vis[v]){ low[u]=min(low[u],dfn[v]); } } int j; if(dfn[u]==low[u]){ atype++; do{ j=stack[--top]; belong[j]=atype; vis[j]=0; }while(j!=u); } } void init(){ cnt=0; memset(head,-1,sizeof(head)); dep=0, top=0, atype=0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(vis,0,sizeof(vis)); memset(belong,0,sizeof(belong)); memset(indeg,0,sizeof(indeg)); memset(outdeg,0,sizeof(outdeg)); } int main(){ //freopen("input.txt","r",stdin); while(~scanf("%d%d",&n,&m)){ init(); for(int i=1;i<=n;i++) scanf("%d",&cost[i]); int u,v; while(m--){ scanf("%d%d",&u,&v); addedge(u,v); } for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i); for(int u=1;u<=n;u++) for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(belong[u]!=belong[v]){ outdeg[belong[u]]++; indeg[belong[v]]++; } } for(int i=1;i<=atype;i++) tcost[i]=INF; for(int i=1;i<=n;i++) //保存缩点后的图的每个点的最小花费 tcost[belong[i]]=min(tcost[belong[i]],cost[i]); int ans=0,total=0; for(int i=1;i<=atype;i++) if(indeg[i]==0){ ans++; total+=tcost[i]; } printf("%d %d\n",ans,total); } return 0; }