把一个强联通分量缩成一个点,点的话费是分量中所有点的话费的最小值,看新图中入度为0的点有多少个,把这些点的话费加起来就行
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
using namespace std;
typedef long long LL;
const int inf=(1LL<<31)-1;
const int maxN=1e3+5;
const int maxM=2e3+5;
int N,M,cost[maxN];
int head[maxN],tol;
struct Graph
{
int from,to,next;
}path[maxM];
void add(int u,int v)
{
path[tol]={u,v,head[u]};
head[u]=tol++;
}
int dfn[maxN],low[maxN],scc[maxN],cnt,scost[maxN];
int insta[maxN],tim;
int in[maxN];
stack<int> sta;
void tarjan(int u)
{
dfn[u]=low[u]=++tim;
sta.push(u);
insta[u]=1;
for(int i=head[u];i!=-1;i=path[i].next)
{
int v=path[i].to;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(insta[v])low[u]=min(low[u],low[v]);
}
if(dfn[u]==low[u])
{
cnt++;
int m;
do
{
m=sta.top();
sta.pop();
insta[m]=0;
scc[m]=cnt;
scost[cnt]=min(scost[cnt],cost[m]);
}while(u!=m);
}
}
int main()
{
while(~scanf("%d%d",&N,&M))
{
int u,v;
memset(head,-1,sizeof(head));
tim=tol=0;
for(int i=1;i<=N;i++)scanf("%d",&cost[i]);
while(M--)
{
scanf("%d%d",&u,&v);
add(u,v);
}
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(scc,0,sizeof(scc));
cnt=0;
for(int i=1;i<=N;i++)scost[i]=inf;
for(int i=1;i<=N;i++)
if(!dfn[i])
tarjan(i);
memset(in,0,sizeof(in));
for(int i=0;i<tol;i++)
{
u=scc[path[i].from];
v=scc[path[i].to];
if(v!=u)in[v]++;
}
int ans1,ans2;
ans1=ans2=0;
for(int i=1;i<=cnt;i++)if(!in[i])ans1++,ans2+=scost[i];
printf("%d %d\n",ans1,ans2);
}
return 0;
}