注意 tarjan 的功能
是求出 强联通量 进行缩点。
最终还需要求一下入度为零的超级点
#include<bits/stdc++.h> using namespace std; #define maxn 2005 #define inf 0x3f3f3f3f int a[maxn]; vector<int>mmp[maxn]; int in[maxn],dfn[maxn],low[maxn],stk[maxn],instk[maxn]; int n,m,u,v,index,cnt,tot,color[maxn],cost[maxn],ans,sum; void tarjan(int u) { int v; low[u]=dfn[u]=++tot; stk[++index]=u; instk[u]=1; for(int j=0; j<mmp[u].size(); j++) { v=mmp[u][j]; if(!dfn[v]) { tarjan(v); low[u]=min(low[v],low[u]); } else if(instk[v])//在栈内才有资格去更新 { low[u]=min(low[u],dfn[v]); } } if(low[u]==dfn[u]) { ++cnt; do { v=stk[index--]; color[v]=cnt; instk[v]=0;//出栈取消标记。 } while(v!=u); } } void solve() { memset(in,0,sizeof(in)); memset(dfn,0,sizeof(dfn)); memset(instk,0,sizeof(instk)); memset(color,0,sizeof(color)); memset(cost,inf,sizeof(cost)); memset(low,0,sizeof(low)); memset(stk,0,sizeof(stk)); cnt=tot=ans=sum=0; index=-1; for(int i=1; i<=n; i++) if(!dfn[i]) tarjan(i); for(int i=1; i<=n; i++) cost[color[i]]=min(cost[color[i]],a[i]); for(int i=1; i<=n; i++) for(int j=0; j<mmp[i].size(); j++) if(color[mmp[i][j]]!=color[i]) in[color[mmp[i][j]]]++; for(int i=1; i<=cnt; i++) if(in[i]==0) { ans+=cost[i]; sum++; } cout<<sum<<" "<<ans<<endl; } int main() { ios::sync_with_stdio(false); while(cin>>n>>m) { for(int i=1; i<=n; i++) { cin>>a[i]; mmp[i].clear(); } while(m--) { cin>>u>>v; mmp[u].push_back(v); } solve(); } return 0; }