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

判断一个由向图是否弱连通(任意两点u与v,u->v和v->u至少有一个成立)

关键词:弱连通、最长路、拓扑排序

做法一:1.建立scc图2.scc图拓扑排序唯一 <=> 弱连通

做法二:1.建立scc图2.scc图的最长路径,最长路径==scc_cnt <=>弱连通(存在一条经过所有点的路径)

法二还可以求最大弱连通子图

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<stack>
#define ll long long
#define INF 0x3f3f3f3f
#define maxn 1002
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;

int t,n,m;
vector<int> g[maxn],scc[maxn];
int pre[maxn],lowin[maxn],sccno[maxn],dfs_clock,scc_cnt;
stack<int> S;
int in[maxn],ans;
int dp[maxn];

void build(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) g[i].clear();
    for(int i=1;i<=m;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        g[a].push_back(b);
    }
}

void dfs(int u){
    lowin[u]=pre[u]=++dfs_clock;
    S.push(u);
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i];
        if(!pre[v]) { dfs(v);lowin[u]=min(lowin[u],lowin[v]); }
        else if(!sccno[v]) lowin[u]=min(lowin[u],pre[v]);
    }
    if(lowin[u]==pre[u]){
        scc_cnt++;
        for(;;){
            int x=S.top();S.pop();
            sccno[x]=scc_cnt;
            if(x==u) break;
        }
    }
}

void find_scc(){
    mem(pre,0),mem(sccno,0),dfs_clock=scc_cnt=0;
    for(int i=1;i<=n;i++) if(!pre[i]) dfs(i);
}

void build_scc(){
    mem(in,0);
    for(int i=1;i<=n;i++) scc[i].clear();
    for(int u=1;u<=n;u++){
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i];
            if(sccno[u]!=sccno[v]) { scc[sccno[u]].push_back(sccno[v]); in[sccno[v]]++; }
        }
    }
}

void top_scc(){
    ans=1;
    for(int i=1;i<=scc_cnt;i++){
        int tmp=0;
        bool flag=true;
        for(int j=1;j<=scc_cnt;j++){
            if(!in[j]){
                if(!tmp) tmp=j;
                else { flag=false; break; }
            }
        }
        if(!flag) { ans=0; break; }
        in[tmp]--;//删除tmp点
        for(int j=0;j<scc[tmp].size();j++){
            int v=scc[tmp][j];
            in[v]--;
        }
    }
}

/*法二
int DP(int u){
    if(dp[u]) return dp[u];
    int ttmp=0;
    for(int i=0;i<scc[u].size();i++){
        int v=scc[u][i];
        ttmp=max(ttmp,DP(v));
    }
    return dp[u]=ttmp+1;
}

void longest_scc(){
    mem(dp,0);
    int tmp=0;
    for(int i=1;i<=n;i++) tmp=max(tmp,DP(i));
    if(tmp==scc_cnt) ans=1;
    else ans=0;
}
*/

int main(){
    //freopen("a.txt","r",stdin);
    scanf("%d",&t);
    while(t--){
        build();
        find_scc();
        build_scc();
        top_scc();//法一
        //longest_scc();//法二
        if(ans) printf("Yes\n");
        else printf("No\n");
    }
}<strong>
</strong>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值