【1827】Summer Holiday

1827
强连通。tarjan+缩点。参考:缩点

#include<bits/stdc++.h>
using namespace std;
const int inf=999999;
struct node{
    int v,u,next;
}edge[2005];
int head[1005],cnt;
int vis[1005],low[1005],dfn[1005],tot; 
int n,m,ans;//ans:缩点的个数( from 1 to ans )
int cost[1005];
int belong[1005],inde[1005];//缩点,入度
stack<int>q;
void init(){
    cnt=0;
    tot=0;
    ans=0;
    memset( vis,0,sizeof( vis ));
    memset( dfn,-1,sizeof(dfn) );
    memset( low,-1,sizeof( low ));
    memset( head,-1,sizeof( head ));
}
//void addedge( int a,int b ){
//    edge[cnt].v=a;
//    edge[cnt].u=b;
//    edge[cnt].next=head[ a ];
//    head[a]=cnt++;
//}
void tarjan(int now){
    dfn[now]=low[now]=tot++;
    vis[now]=1;
    q.push(now);
    for(int i=head[now];i!=-1;i=edge[i].next){
        int nex=edge[i].u;
        if( dfn[nex]==-1 ){
            tarjan(nex);
            low[now]=min(low[now],low[nex]);
        }
        else if(vis[nex]==1){
            low[now]=min(low[now],dfn[nex]);
        }
    }
    if(low[now]==dfn[now]){
        ans++;
        while(1){
            int tmp;
            tmp=q.top(),q.pop();
            vis[tmp]=0;
            belong[tmp]=ans;
            if(tmp==now) break;
        }
    }
}
 
int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i=1;i<=n;i++)
            scanf("%d",&cost[i]);
        init();
        int a,b;
        while(m--){
            scanf("%d%d",&a,&b);
//            addedge( a,b );
		    edge[cnt].v=a;
    		edge[cnt].u=b;
    		edge[cnt].next=head[a];
   			head[a]=cnt++;
        }
        while(!q.empty()) 
			q.pop();
        for(int i=1;i<=n;i++){
            if(dfn[i]==-1){
                tarjan(i);
            }
        }
        memset(inde,0,sizeof(inde));
        for( int i=0;i<cnt;i++ ){
            a=edge[i].v,b=edge[i].u;
            if( belong[a]!=belong[b] ){
                inde[ belong[b] ]++;
            }
        }
        int ANS1,ANS2;
        ANS1=ANS2=0;
        int tmp_cnt[1005];
        for( int i=1;i<=ans;i++ ){
            if( inde[i]==0 )
                ANS1++;//统计缩点之后入度为0的点
            tmp_cnt[i]=inf;
        }
        for(int i=1;i<=n;i++){
            int tmp=belong[i];
            if(inde[tmp]==0){
                tmp_cnt[tmp]=min(tmp_cnt[tmp],cost[i]);
            }
        }
        for(int i=1;i<=ans;i++){
            if( tmp_cnt[i]!=inf)
                ANS2+=tmp_cnt[i];
        }
        printf("%d %d\n",ANS1,ANS2);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值