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求一遍tarjan ,一个强连通分量就只需通知一个人就行了,这个人就可以通知到同一个强连通分量里面的人 ;缩点,如果有 u->v ; 说明u通知了,v这个强连通分量的也通知到了 ; 所以 缩点建图后,只要入读为0的那些点,就是要通知的人 ;每一个强连通分量记录里面花费最小的费用 ;#include<cstdio> #include<cstring> #include<map> #include<vector> #include<cmath> #include<cstdlib> #include<queue> #include <iomanip> #include<iostream> #include<algorithm> using namespace std ; const int N=2000 ; const int M=3000 ; const int inf=1<<30 ; struct node { int u,v,next ; }edge[M] ; int head[N] ,low[N],dnf[N],vis[N],stack[N],in[N],belong[N],cost[N],f[N]; int dep,cnt,top,sum ; void add(int u ,int v) { edge[top].u=u ; edge[top].v=v; edge[top].next=head[u] ; head[u]=top++; } void tarjan(int u) { int x ; low[u]=dnf[u]=++dep ; stack[cnt++]=u; vis[u]=1; for(int i = head[u] ; i!=-1; i=edge[i].next) { int v=edge[i].v ; if(!dnf[v]) { tarjan(v) ; low[u] = min( low[u] , low[v]) ; } else if(vis[v]) low[u] = min( low[u] , dnf[v] ) ; } if(low[u]==dnf[u]) { sum++ ; int z=inf ; do { x = stack[--cnt] ; vis[x] = 0 ; belong[x]=sum; z = min(z,f[x]) ; }while(x!=u) ; cost[sum] = z ;//更新一个联通分支花费最小的 ; } } int main() { int n,m ,u,v; while(~scanf("%d%d",&n,&m)) { top = 0 ; memset(head,-1,sizeof(head)) ; for(int i = 1 ; i <= n;i++) scanf("%d",&f[i]) ; for(int i = 1 ; i <= m ; i++) { scanf("%d%d",&u,&v) ; add(u,v) ; } memset(low,0,sizeof(low)) ; memset(dnf,0,sizeof(dnf)) ; memset(vis,0,sizeof(vis)) ; memset(in,0,sizeof(in)) ; dep=sum=cnt=0 ; for(int i = 1 ; i <= n ; i++) { if(!dnf[i]) tarjan(i) ; } for(int i = 1 ; i <= n ; i++)//缩点 { for(int j = head[i] ; j!=-1 ;j=edge[j].next) { v=edge[j].v ; if(belong[i]!= belong[v])//不同强连通分支 { in[belong[v]]++ ;//记录入读 } } } int ans = 0 , num= 0 ; for(int i = 1 ; i <= sum ; i++) { if(!in[i])//入读为0的强联通分量要通知 { ans += cost[i] ; num++; } } printf("%d %d\n",num ,ans) ; } return 0 ; }