POJ 2762 Going from u to v or from v to u? - 缩点 - DAG最长链

题目大意是,判断一个有向图中所有的任意两点x,y,是否满足,从x可以走到y 或者 从y可以走到x

很显然,同一个SCC中的所有点一定满足这个条件,当同一个SCC中的所有点要么同时选要么同时不选的时候,就可以缩点了。缩点的方法就是给每个点加一个强联通分量编号(染色),然后tarjan结束后考察每一条边,若某条边的两头不是同一个颜色,就加一条新边。

缩点后的图一定是一个DAG(有向无环图),在这张新图上可以得到一个结论:若满足题目要求的条件,这个新图是不能有分叉的,因为一旦有了分叉,就会有叶节点,而叶节点是无法走到比其本身更深的点的,同样一个比叶节点更深的点也无法走回叶节点(图是有向的)

现在求的就是这个新图的最长链(如果判断出有分叉直接返回0),如果最长链等于新图点数(因为有可能会出现孤立的点),那么这张图便是可行的。

若最长链长度等于缩点后点数,就代表没有分叉
注意多组数据清空DP数组!!!

可能这张图不连通,并且一张有向图并不一定能从一个点出发到所有点,所以循环一遍

for(int i=1; i<=n; i++)
    if(!dfn[i]) tarjan(i);
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <cstring>
using namespace std;
const int maxn = 6010;
#define debug(x) cerr << #x << "=" << x << endl;
#define mmm(x) memset(x,0,sizeof(x));
int t,n,m,last[maxn],tot,l,dfn[maxn],low[maxn],color[maxn],sccnum;
int tot_new,last_new[maxn],n_new,chain,cou,dp[maxn];
int id[maxn], od[maxn];
bool ans, flg[maxn];
stack <int> s;
struct Edge{
    int u,v,to;
    Edge(){}
    Edge(int u, int v, int to): u(u), v(v), to(to) {}
}e[maxn];

inline void addedge(int u, int v) {
    e[++tot] = Edge(u,v,last[u]);
    last[u] = tot;
}

void tarjan(int x) {
    dfn[x] = low[x] = ++cou;
    s.push(x);
    flg[x] = true;
    for(int i=last[x]; i; i=e[i].to) {
        if(!dfn[e[i].v]) {
            tarjan(e[i].v);
            if(low[e[i].v] < low[x]) low[x] = low[e[i].v];
            
        } else if(dfn[e[i].v] < low[x] && flg[e[i].v]){
            low[x] = dfn[e[i].v];
        }
    }
    if(dfn[x]==low[x]) {
        int fr,num;
        sccnum++; //ÐÂͼÖеĵãÊý 
        do {
            fr = s.top();
            s.pop();
            flg[fr] = 0;//³öÕ»ÁË 
            num++;
            color[fr] = sccnum;
        }while(fr != x);
    }
}

struct Edge_new{
    int u,v,to;
    Edge_new(){}
    Edge_new(int u, int v, int to): u(u), v(v), to(to) {}
}e_new[maxn];

inline void addedge_new(int u, int v) {
    e_new[++tot_new] = Edge_new(u,v,last_new[u]);
    last_new[u] = tot_new;
} 

queue <int> q;

bool topo() {
    for(int i=1; i<=sccnum; i++) {
        if(id[i] == 0) 
            dp[i] = 1, q.push(i);
    }
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        for(int i=last_new[u]; i; i=e_new[i].to) {
            int v = e_new[i].v;
            id[v]--;
            dp[v] = max(dp[v], dp[u] + 1);
            if(!id[v]) q.push(v);
        }
    }
    for(int i=1; i<=sccnum; i++) 
        if(dp[i] == sccnum) return true;
    return false;
}

bool solve() {
    for(int i=1; i<=tot; i++) {
        int u = e[i].u, v = e[i].v;
        if(color[u] != color[v]) {
            addedge_new(color[u],color[v]);
            od[color[u]]++;
            id[color[v]]++;
        }
    }
    if(topo()) return true;
    else return false;
}

int main() {
    scanf("%d",&t);
    while(t--) {
        mmm(dfn);mmm(low);mmm(color);mmm(last);mmm(flg);
        mmm(last_new);mmm(e);mmm(e_new);mmm(id);mmm(od);mmm(dp);
        tot = 0;cou = sccnum = tot_new = chain = 0;
        while(!s.empty())
            s.pop();
        while(!q.empty())
            q.pop();    
        ans = 0;
        scanf("%d %d", &n, &m);
        for(int i=1; i<=m; i++) {
            int u, v;
            scanf("%d %d", &u, &v);
            addedge(u,v);
        }
        for(int i=1; i<=n; i++) {
            if(!dfn[i]) tarjan(i);
        }
        if(solve()) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

转载于:https://www.cnblogs.com/Zolrk/p/9867332.html

微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码 微信小程序毕业设计期末大作业项目源码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值