UOJ Logo zgjkt的博客

博客

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

2015-09-06 13:46:16 By zgjkt

题目大意

给一个有n个点m条边的有向图,对于图中任意两个点u,v,如果从u能到v,或者从v能到u,则这对顶点是可行的

如果图中任意一对顶点都是可行的,可以输出Yes,否则输出No

数据范围

$0< n< 1001,m< 6000$


题解

在这个有向图中,强连通分量一定满足条件,所以我们首先要强联通分量缩点构建新图

新图一定是一个DAG,在这个DAG中,如果最长链的长度=新图的大小,那么就意味着满足了条件

那么我们就可以强连通分量缩点之后,从新图的每一个点出发跑一次dp最长路找出最长链,判断是否为新图的大小


程序

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define For(i,l,r) for(int i=l;i<=r;i++)
using namespace std;

const int maxn=1050,maxm=6050;
struct edge{int to,next;}e[maxm],e2[maxm];
int last[maxn],last2[maxn],belong[maxn],opt[maxn];
int dfn[maxn],low[maxn],flag[maxn],q[maxn];
int n,m,dfn_tot,scc_tot,top,et,et2,f,t;

inline void addedge(int u,int v){e[++et].to=v;e[et].next=last[u];last[u]=et;}
inline void addedge2(int u,int v){e2[++et2].to=v;e2[et2].next=last2[u];last2[u]=et2;}
inline void makenothing(){
    memset(last,0,sizeof(last));memset(last2,0,sizeof(last2));
    memset(belong,0,sizeof(belong));memset(flag,0,sizeof(flag));
    memset(opt,-1,sizeof(opt));memset(q,0,sizeof(q));
    memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));
    scc_tot=dfn_tot=et=et2=top=f=0;
}

void tarjan(int x){
    low[x]=dfn[x]=++dfn_tot;
    flag[x]=1;q[++top]=x;
    for(int i=last[x];i;i=e[i].next)
        if (!dfn[e[i].to]){tarjan(e[i].to);low[x]=min(low[x],low[e[i].to]);}
        else if (flag[e[i].to]) low[x]=min(low[x],dfn[e[i].to]);
    if (low[x]==dfn[x]){
        scc_tot++;
        int now=0;
        while(now!=x){
            now=q[top--];
            belong[now]=scc_tot;
            flag[now]=0;
        }
    }
}
int dp(int x){  
    if (opt[x]!=-1) return opt[x];  
    int sum=0;  
    for (int i=last2[x];i;i=e2[i].next) sum=max(sum,dp(e2[i].to));    
    opt[x]=++sum;  
    return sum;  
}  
int main(){
    scanf("%d",&t);
    while(t--){
        makenothing();
        scanf("%d%d",&n,&m);
        For(i,1,m){
            int x,y;scanf("%d%d",&x,&y);
            addedge(x,y);
        }
        For(i,1,n) if (!dfn[i]) tarjan(i);
        For(u,1,n)
            for(int i=last[u];i;i=e[i].next)
                if (belong[u]!=belong[e[i].to]) addedge2(belong[u],belong[e[i].to]);
        int ans=0;
        For(i,1,scc_tot) ans=max(ans,dp(i));
        if (ans==scc_tot) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。