poj2762 Going from u to v or from v to u?

poj 2762

给定一个有向图,问任意两点能否满足u能到v,或者,v能到u。共有n个点,m条边,(\(0<n<1001, 0<m<6000\))。

  这道题应该是判断弱连通图。首先肯定是缩点,然后出来一个dag。我按照课件里说的,首先想到判断出度和入度为零的点的个数是否大于1,但这个是错的,因为在一个橄榄状的图中,几个分叉的点不能到达彼此。所以只有橄榄状且没有分叉的图才是yes。也就等于从源点判断最长路为n的图,它才是yes。这样才A。

#include <cstdio>
#include <cstring>
using namespace std;
inline int min(int x, int y){ return x<y?x:y; }
inline int max(int x, int y){ return x<y?y:x; }

const int maxn=1005, maxm=6005;
class Graph{
public:
    struct Edge{
        int to, next; Graph *belong;
        Edge& operator ++(){
            *this=belong->edge[next];
            return *this;
        }
        int operator *(){ return to; }
    };
    void reset(){
        cntedge=0;
        edge[0].to=-1;
        memset(fir, 0, sizeof(fir));
    }
    void addedge(int x, int y){
        Edge &e=edge[++cntedge];
        e.to=y, e.next=fir[x];
        e.belong=this, fir[x]=cntedge;
    }
    Edge getlink(int x){ return edge[fir[x]]; }
private:
    Edge edge[maxm];
    int cntedge, fir[maxn];
};
Graph g, g_scc;
int tt, n, m, time, dfn[maxn], low[maxn];
int t, stack[maxn], instack[maxn];
int cntscc, incnt, belong[maxn], in[maxn], dp[maxn];

void tarjan(int now){
    //注意tarjan不用考虑父亲!
    int nowc;
    dfn[now]=low[now]=++time;
    stack[++t]=now; instack[now]=1;
    for (Graph::Edge e=g.getlink(now); ~*e; ++e){
        nowc=*e;
        if (instack[nowc])
            low[now]=min(low[now], dfn[nowc]);
        if (!dfn[nowc]){
            tarjan(nowc);
            low[now]=min(low[now], low[nowc]);
        }
    }
    if (dfn[now]==low[now]){
        ++cntscc;
        //这里只能用dowhiles
        do{
            belong[stack[t]]=cntscc;
            instack[stack[t]]=0;
            --t;
        }while (dfn[stack[t+1]]!=low[stack[t+1]]);
    }
}

int dfs(int now){
    int nc, re=0;
    for (Graph::Edge e=g_scc.getlink(now); ~*e; ++e){
        nc=*e;
        if (!dp[nc]) re=max(dfs(nc), re);
        else re=max(dp[nc], re);
    }
    dp[now]=re+1;
    return re+1;
}

void init(){
    g.reset(); g_scc.reset();
    time=0; cntscc=0; incnt=0;
    memset(dp, 0, sizeof(dp));
    memset(in, 0, sizeof(in));
    memset(dfn, 0, sizeof(dfn));
    memset(low, 0, sizeof(low));
}

//考虑中途分叉的情况!所以只能跑dag最长路!
int main(){
    scanf("%d", &tt);
    int x, y, nc, start;
    while (tt--){
        init();
        scanf("%d%d", &n, &m);
        for (int i=0; i<m; ++i){
            scanf("%d%d", &x, &y);
            g.addedge(x, y);
        }
        for (int i=1; i<=n; ++i)
            if (!dfn[i]) tarjan(i);
        for (int i=1; i<=n; ++i)
            for (Graph::Edge e=g.getlink(i); ~*e; ++e){
                nc=*e;
                if (belong[i]!=belong[nc]){
                    g_scc.addedge(belong[i], belong[nc]);
                    ++in[belong[nc]];
                }
            }
        for (int i=1; i<=cntscc; ++i)
            if (!in[i]) start=i;
        if (dfs(start)==cntscc) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}
posted @ 2017-09-30 09:37  pechpo  阅读(124)  评论(0编辑  收藏  举报