zoukankan      html  css  js  c++  java
  • [暑假集训]开训复健练习赛 E

    #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.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
    ",cnt,sum);
        }
        return 0;
    }

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

  • 相关阅读:
    5 November
    31 October
    K-th Path
    P1525 关押罪犯
    dp-棋盘形dp
    P1462 通往奥格瑞玛的道路
    noip2017部分题目
    洛谷orz--尺取法
    树形dp
    最短路练习
  • 原文地址:https://www.cnblogs.com/forwhat00/p/13357592.html
Copyright © 2011-2022 走看看