HDU 6165-强连通分量+拓扑

Posted 水明

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 6165-强连通分量+拓扑相关的知识,希望对你有一定的参考价值。

题意

给出一幅有向图,判定是否存在一对顶点互相不可达。

分析

在一个强连通分量里的点对是互相可达的,我们先求出强连通分量再缩点构建新图

然后我们对新图进行拓扑排序,当开始时或者删完一个点及它的关联边时,若入度为0的点多于1个,则这些点互相不可达

代码

#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define MAX     10007
#define MAXN      10007
#define MAXM      20007
#define INF  0x3f3f3f3f
#define NINF 0xc0c0c0c0
#define MOD  1000000007
using namespace std;
typedef long long LL;
struct Edge{int to,next;}edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];//Belong数组的值是1~scc
int Index,top;
int scc;//强连通分量的个数
bool Instack[MAXN];
int num[MAXN];//各个强连通分量包含点的个数,数组编号1~scc
//num数组不一定需要,结合实际情况
void addEdge(int u,int v) {
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
void Tarjan(int u) {
    int v;
    Low[u]=DFN[u]=++Index;
    Stack[top++]=u;
    Instack[u]=true;
    for(int i=head[u];i!=-1;i=edge[i].next){
        v=edge[i].to;
        if(!DFN[v]){
            Tarjan(v);
            if(Low[u]>Low[v])Low[u]=Low[v];
        }
        else if(Instack[v]&&Low[u]>DFN[v])
            Low[u]=DFN[v];
    }
    if(Low[u]==DFN[u]){
        scc++;
        do{
            v=Stack[--top];
            Instack[v]=false;
            Belong[v]=scc;
            num[scc]++;
        }while(v!=u);
    }//printf("scc=%d\n",scc);
}
void solve(int N) {
    memset(DFN,0,sizeof DFN);
    memset(Instack,false,sizeof Instack);
    memset(num,0,sizeof num);
    Index=scc=top=0;
    for(int i=1;i<=N;i++)
        if(!DFN[i])Tarjan(i);
}
Edge edge1[MAXM];
int tot1,head1[MAXN],odeg1[MAXN],indegree[MAXN];
void addEdge1(int u,int v) {
    odeg1[u]++;
    indegree[v]++;
    edge1[tot1].to=v;
    edge1[tot1].next=head1[u];
    head1[u]=tot1++;
}
void reduce(int N){
    tot1=0;
    memset(head1,-1,sizeof head1);
    memset(odeg1,0,sizeof odeg1);
    memset(indegree,0,sizeof indegree);
    for(int u=1;u<=N;u++){
        for(int k=head[u];k!=-1;k=edge[k].next){
            int v=edge[k].to;
            if(Belong[u]!=Belong[v]){
                addEdge1(Belong[u],Belong[v]);
            }
        }
    }
}
bool topo(int n){
    priority_queue<int, vector<int>,greater<int> > Q;
    int ans[MAXN],iq=0;
    for(int i=1;i<=n;i++){
        //printf("%d\n",indegree[i]);
        if(indegree[i]==0) Q.push(i);
    }
    //
    if(Q.size()!=1)return false;//printf("flag1\n");
    while(!Q.empty()){//printf("sizeof q is %d\n",Q.size());
        if(Q.size()!=1)return false;
        int qt=Q.top();
        ans[iq++]=qt;
        Q.pop();
        for(int k=head1[qt];k!=-1;k=edge1[k].next){
            int t=edge1[k].to;
            indegree[t]--;
            if(indegree[t]==0) Q.push(t);
        }
    }
    return true;
}
void init() {
    tot=0;
    memset(head,-1,sizeof head);
}

int main(){
    int cas,n,m,u,v;
    scanf("%d",&cas);
    while(cas--){
        init();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            addEdge(u,v);
        }
        solve(n);
        reduce(n);
        printf(topo(scc)?"I love you my love and our love save us!\n"
        :"Light my fire!\n");
    }
    return 0;
}

  

以上是关于HDU 6165-强连通分量+拓扑的主要内容,如果未能解决你的问题,请参考以下文章

HDU 1269 迷宫城堡 tarjan算法求强连通分量

HDU 3836 Equivalent Sets(强连通分量)

强连通分量与拓扑排序略解

2017 Multi-University Training Contest - Team 9 1005&&HDU 6165 FFF at Valentine强联通缩点+拓扑排序((代

HDU1269tarjan求强连通分量

hdu1269:强连通分量