forwhat00  
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
#define DEBUG if(1)
const int MAXN = 1010;//点数
const int MAXM = 2010;//边数

class POINT{public:
    int next[MAXM],num,DFN,Low,Instack,Belong;
    void RESET(){//Belong的值是1~scc
        num=0;DFN=Instack=0;
    }
    void add(int b){
        next[num++]=b;
    }
}P[MAXN];

int head[MAXN],N,M,Stack[MAXN];
int Index,top;
int scc;//强连通分量的个数
bool Instack[MAXN];
int num[MAXN];
//各个强连通分量包含点的个数,数组编号1~scc
//num数组不一定需要,结合实际情况
void Tarjan(int u){
    int v;
    P[u].Low = P[u].DFN = ++Index;
    Stack[top++] = u;
    P[u].Instack = true;
    for(int i=0;i<P[u].num;i++){//遍历所有下一节点
        v = P[u].next[i];
        if( !P[v].DFN ){
            Tarjan(v);
            if( P[u].Low > P[v].Low )P[u].Low = P[v].Low;//使可回溯最初始点最小
        }else if(P[v].Instack && P[u].Low > P[v].DFN)//遍历到遍历过的点
            P[u].Low = P[v].DFN;//说明循环了,记录
    }
    if(P[u].Low == P[u].DFN){
        //最小可回溯点与当前点编号相等说明该点是一个强联通子图初始点
        scc++;
        do{
            v = Stack[--top];
            P[v].Instack = false;
            P[v].Belong = scc;//该点所属子图编号
            num[scc]++;
        }while( v != u);
    }
}
void solve(int N){
    for(int i = 1; i <= N; i++)
        if(!P[i].DFN)//确保遍历所有节点
            Tarjan(i);
}
int main(){
    int fee[MAXN];
    memset(fee,0,sizeof(fee));

    while(cin>>N>>M){
        if(M==0||N==0)break;

        memset(num,0,sizeof(num));
        Index = scc = top = 0;//初始化
        for(int i=1;i<=N;i++)P[i].RESET();

        for(int i=1;i<=N;i++)scanf("%d",&fee[i]);

        for(int i=0;i<M;i++){
            int a,b;cin>>a>>b;
            P[a].add(b);//加入边
        }
        solve(N);

        int mfee[MAXN]={0};  //记录每个强连通图集的最小话费
        bool inode[MAXN]={false}; //不可达连通图
        int cnt=0;//记录多少个不可达连通图
        DEBUG{
            for(int i=1;i<N;i++){
                POINT & t=P[i];//输出所有节点的编号等
                cout<<i<<" DFN="<<t.DFN
                    <<" Low="<<t.Low
                    <<" Belong="<<t.Belong
                    <<endl;
                for(int j=0;j<t.num;j++){
                    cout<<"\t->"<<t.next[j]<<endl;
                }
            }
        }
        for(int i=0;i<=N;i++){
            POINT & t=P[i];
            for(int j=0;j<t.num;j++){
                int tt=P[t.next[j]].Belong;
                if(t.Belong!=tt){
                    //当前点与下一点所属强联通子图编号不同
                    //说明下一强联通子图需要另算费用
                    inode[tt]=true;
                }
            }
        }
        for(int i=1;i<=scc;i++){
            if(!inode[i]) cnt++;
            mfee[i]=1e9;
        }
        for(int i=1;i<=N;i++){
            int t=P[i].Belong;
            if(!inode[t])
                mfee[t]=min(mfee[t],fee[i]);
        }
        int sum=0;
        for(int i=1;i<=scc;i++)
            if(mfee[i]!=1e9) sum+=mfee[i];
        printf("%d %d\n",cnt,sum);
    }
    return 0;
}

https://vjudge.net/contest/382410#problem/E

posted on 2020-07-21 21:37  forwhat00  阅读(200)  评论(0编辑  收藏  举报