1 /**************************************************** 2 3 Summer Holiday(hdu 1827) 4 http://acm.hdu.edu.cn/showproblem.php?pid=1827 5 强连通 6 先通过tarjan找出强连通分量,强连通分量入度为零 7 的就一定要打电话,所以入度为零就是最少要打的电 8 话数,然后对每个强连通分量找最小值就是最少话费 9 10 ****************************************************/ 11 12 #include<cstdio> 13 #include<cstring> 14 #include<algorithm> 15 #include<vector> 16 #include<stack> 17 using namespace std; 18 19 const int mx=1005; 20 vector<int>g[mx]; 21 stack<int>s; 22 int dfn[mx],low[mx]; 23 int vs[mx],sccno[mx]; 24 int a[mx],ans[mx],in[mx]; 25 int dfs_cut,scc_cut; 26 27 void Init(int n) 28 { 29 dfs_cut=scc_cut=0; 30 memset(dfn,0,sizeof(dfn)); 31 memset(low,0,sizeof(low)); 32 memset(vs,0,sizeof(vs)); 33 memset(in,0,sizeof(in)); 34 memset(ans,0,sizeof(ans)); 35 memset(sccno,0,sizeof(sccno)); 36 for (int i=1;i<=n;i++) g[i].clear(); 37 while (!s.empty()) s.pop(); 38 } 39 40 41 void dfs(int u) 42 { 43 vs[u]=1; 44 s.push(u); 45 low[u]=dfn[u]=++dfs_cut; 46 for (int i=0;i<g[u].size();i++) 47 { 48 int v=g[u][i]; 49 if (!vs[v]) 50 { 51 dfs(v); 52 low[u]=min(low[u],low[v]); 53 } 54 else if (!sccno[v]) low[u]=min(low[u],dfn[v]); 55 } 56 if (low[u]==dfn[u]) 57 { 58 scc_cut++; 59 while(1) 60 { 61 int x=s.top(); 62 s.pop(); 63 sccno[x]=scc_cut; 64 if (x==u) break; 65 } 66 } 67 } 68 69 70 int main() 71 { 72 int n,m,i,j; 73 while (~scanf("%d%d",&n,&m)) 74 { 75 Init(n); 76 for (i=1;i<=n;i++) scanf("%d",&a[i]); 77 int u,v; 78 while(m--) 79 { 80 scanf("%d%d",&u,&v); 81 g[u].push_back(v); 82 } 83 84 for (i=1;i<=n;i++) 85 { 86 if (!vs[i]) dfs(i); 87 } 88 for (i=1;i<=n;i++) 89 { 90 for (j=0;j<g[i].size();j++) 91 { 92 int v=g[i][j]; 93 if (sccno[i]!=sccno[v]) in[sccno[v]]=1; 94 } 95 } 96 for (i=1;i<=n;i++) 97 { 98 if (!in[sccno[i]]) 99 { 100 if (!ans[sccno[i]]) ans[sccno[i]]=a[i]; 101 else ans[sccno[i]]=min(ans[sccno[i]],a[i]); 102 } 103 } 104 int ans1=0,cut=0; 105 for (i=1;i<=scc_cut;i++) 106 { 107 ans1+=ans[i]; 108 if (ans[i]) cut++; 109 } 110 printf("%d %d\n",cut,ans1); 111 } 112 }