1.强连通分量:
强连通分量可以理解为边数最少的情况下是一个环。
这里写了一个模板题用的是tarjan算法,当然还有其他算法。
tarjan算法的关键其实还是对于num数组和low数组的使用
然后可以用栈来分离不同的ssc
感觉跟双边连通分量有异曲同工之妙

第一题hdu1296

#pragma GCC optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <math.h>
#include <string>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <stdlib.h>
#define maxn 20010
//#define true false
//#define false true
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
const double pi = acos(-1);
typedef long long ll;
const int mod = 1e9 + 7;
using namespace std;
int n,m;
vector < vector<int> > maps;
int low[maxn];
int num[maxn];
int stacks[maxn],ssc[maxn];
int dfsnum=0,top,cnt;
void init(){
    memset(low,0,sizeof(low));
    memset(num,0,sizeof(num));
    memset(ssc,0,sizeof(ssc));
    dfsnum=0;
    top=0;
    cnt=0;
}
void dfs(int u){
    stacks[top++]=u;
    low[u]=num[u]=++dfsnum;
    for(int i=0;i<maps[u].size();i++){
        int v=maps[u][i];
        if(!num[v]){
            dfs(v);
            low[u]=min(low[v],low[u]);
        }
        else if(!ssc[v])  low[u]=min(low[u],num[v]);  //处理回退边
    }
    if(low[u]==num[u]){   //栈底的点是ssc的祖先,low=num值
        cnt++;
        while(true){
            int v=stacks[--top];
            ssc[v]=cnt;
            if(u==v)  break;
        }
    }
}

void tarjan(){
    init();
    for(int i=1;i<=n;i++)   //因为最少便的情况下是一个环,所以说从哪个点开始走,都可以回到原始点
        if(!num[i])  dfs(i);
}



int main()
{
    while(scanf("%d%d",&n,&m)&&n){
        init();
        maps.clear();
        maps.resize(10010);
        for(int i=0;i<m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            maps[x].push_back(y);
        }
        tarjan();
        if(cnt>1)  printf("No\n");
        else printf("Yes\n");
    }
    return 0;
}

第二题hdu1827
这个还是先用tarjan算法来求有多少个强连通分量,然后我们再用缩点的思想把一个强连通量当一个点来看,因为要最少的人,相当于找入度0的人来打电话。

#pragma GCC optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <math.h>
#include <string>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <stdlib.h>
#define maxn 2010
//#define true false
//#define false true
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
const double pi = acos(-1);
typedef long long ll;
const int mod = 1e9 + 7;
using namespace std;
int n,m;
vector < vector<int> > maps;
int low[maxn];
int num[maxn];
int stacks[maxn],ssc[maxn];
int dfsnum=0,top,cnt;
int price[maxn];
int cost[maxn];
int degree[maxn];
void init(){
    memset(low,0,sizeof(low));
    memset(num,0,sizeof(num));
    memset(ssc,0,sizeof(ssc));
    memset(degree,0,sizeof(degree));
    memset(cost,MaxN,sizeof(cost));
    dfsnum=0;
    top=0;
    cnt=0;
}
void dfs(int u){
    stacks[top++]=u;
    low[u]=num[u]=++dfsnum;
    for(int i=0;i<maps[u].size();i++){
        int v=maps[u][i];
        if(!num[v]){
            dfs(v);
            low[u]=min(low[v],low[u]);
        }
        else if(!ssc[v])  low[u]=min(low[u],num[v]);
    }
    if(low[u]==num[u]){
        cnt++;
        while(true){
            int v=stacks[--top];
            ssc[v]=cnt;
            cost[cnt]=min(cost[cnt],price[v]);
            if(u==v)  break;
        }
    }
}
void tarjan(){
    for(int i=1;i<=n;i++)
        if(!num[i]){
            dfs(i);
        }
    for(int i=1;i<=n;i++){
        for(int f=0;f<maps[i].size();f++){
            if(ssc[i]!=ssc[maps[i][f]])  degree[ssc[maps[i][f]]]++;
        }
    }
    int ans1=0,ans2=0;

    //for(int i=1;i<=n;i++) cout<<degree[i]<<" ";

    for(int i=1;i<=cnt;i++){
        if(degree[i]==0)  ans2+=cost[i],ans1++;
    }
    printf("%d %d\n",ans1,ans2);
}



int main()
{
    while(scanf("%d%d",&n,&m)!=EOF){
        init();
        maps.clear();
        maps.resize(1010);
        for(int i=1;i<=n;i++)  scanf("%d",&price[i]);

        for(int i=0;i<m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            maps[x].push_back(y);
        }
        tarjan();
    }
    return 0;
}