1827 tarjan+缩点

#include<stdio.h>
#include<stack>
#include<iostream>
#include<string.h>
#include<vector>
#include<string>
using namespace std;
#define inf 1000000000
#define N 2100
vector<int>h[N];//
stack<int>q;///
int dfn[N],low[N],index,indegree[N],a[N],visit[N],suo[N],fee[N],yong;
int min(int a,int b) {
return a>b?b:a;
}
void tarjan(int u) {
int i;
dfn[u]=low[u]=++index;
visit[u]=1;
q.push(u);
for(i=0;i<h[u].size();i++) {
int v=h[u][i];
if(!dfn[v]) {
tarjan(v);
low[u]=min(low[u],low[v]);//
}
else
if(visit[v]==1) //在寨中
low[u]=min(low[u],low[v]);
}
if(dfn[u]==low[u]) {//如果存在一个强连通分量就将里面的出寨
yong++;
int t;
do {
   t=q.top();
q.pop();
visit[t]=2;//已经浏览过了
suo[t]=yong;//讲一个连通分量置为一个点
            if(fee[yong]>a[t])//求出缩点中最小的费用
fee[yong]=a[t];
}while(t!=u);

}
}
int main() {
int n,m,i,j,count,num;
while(scanf("%d%d",&n,&m)!=EOF) {
while(!q.empty()) 
q.pop();
for(i=1;i<=n;i++) {//输入和初始化
scanf("%d",&a[i]);
h[i].clear();
fee[i]=inf;
}
while(m--) {
scanf("%d%d",&i,&j);//
h[i].push_back(j);//

memset(visit,0,sizeof(visit));
index=0;yong=0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
for(i=1;i<=n;i++)
if(visit[i]!=2)//是否已经入过寨
tarjan(i);
count=0;
memset(indegree,0,sizeof(indegree));
for(i=1;i<=n;i++) 
for(j=0;j<h[i].size();j++) 
  if(suo[i]!=suo[h[i][j]])//如果不是同一个缩点
  indegree[suo[h[i][j]]]++;
  num=0;
  for(i=1;i<=yong;i++)
  if(indegree[i]==0) {//找入度为零的点
  count+=fee[i];
  num++;
  }
  printf("%d %d ",num,count);
}
return 0;
}

原文地址:https://www.cnblogs.com/thefirstfeeling/p/4410860.html