#include<iostream>
#include<string.h>
using namespace std;
int stack[1010],top ,size, step ,color;
int in[1010],dfn[1010],low[1010];
int rd[1010],price[1010],sum,num;
struct E
{
int v, next;
}e[2010];
int head[1010],val[1010],lian[1010];
int n,m;
void init()
{
for(int i=0;i<1010;i++) {stack[i]=in[i]=dfn[i]=low[i]=lian[i]=rd[i]= 0; head[i]=-1;}
top=-1; size=step=color=sum=num=0;
return;
}
void insert(int u, int v)
{
e[size].v=v; e[size].next=head[u]; head[u]=size++;
}
void tarjan(int u)
{
int v;
dfn[u]=low[u]=++step;
stack[++top]=u; //将未访问过的点入栈
in[u]=1; //标记u在栈中
for(int i=head[u];i!=-1; i=e[i].next)
{
v=e[i].v;
if(!dfn[v]) //若未访问过
{
tarjan(v);
if(low[v]<low[u]) low[u]=low[v]; //若点v有边e(v,x)能够连到u之前访问过的点
//因为dfn[x]<dfn[u],且x在栈中,则x一定可以间接或直接访问到u,
//则该子树追溯到得更早的节点为x。所以low[u]=low[v];
}
else if(in[v]) //若该点还在栈中,则v一定在u之前被访问此时该子树追溯到的更早的节点
//可能是low[u](若low[u]点在v点之前被访问即low[u]>dfn[v]),也可能是v点
{
if(dfn[v]<low[u]) low[u]=dfn[v];
}
}
if(low[u]==dfn[u]) //当与最原始u相关的点都访问过后,low[u]为u所在子树追溯到得
// 最早的点x,low[x]=x.于是形成了环(连通分支)
{
color++;
do
{
v=stack[top--];
lian[v]=color; in[v]=0;
}while(v!=u); //由于low[]取得是最早入栈的,所以x在栈中一定位于该分支所有点的下面
}
}
void countRd()
{
for(int i=0;i<=color;i++) price[i]=9999999;
for(int i=1;i<=n;i++)
{
if(price[lian[i]]>val[i]) {price[lian[i]]=val[i];}
}
for(int i=1;i<=n;i++)
{
for(int j=head[i]; j!=-1; j=e[j].next)
{
int v=e[j].v;
if(lian[i]!=lian[v])
rd[lian[v]]++;
}
}
for(int i=1;i<=color;i++) if(rd[i]==0) num++,sum+=price[i];
}
int main()
{
int a, b;
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(int i=1;i<=n;i++) scanf("%d",&val[i]);
for(int i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
insert(a,b);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
countRd();
printf("%d %d\n",num,sum);
}
return 0;
}
hdu 1827 Summer Holiday (Tarjan算法)
最新推荐文章于 2021-11-27 22:37:25 发布