UVA - 11324 The Largest Clique (DAG + 强连通分量)

题目大意:给出一张有向图G,求一个结点数最大的结点集,使得该点集中任意两个结点u和v满足:

要么u可到达v,要么v可以到达u(u和v互相可达也可以)

解题思路:u和v相互可达的时候,就是两个结点在同一个强连通分量内的时候

首先要保证集合里面的点可达:强连通分量就满足集合内的点都相互可达。所以第一件事就是找出所有的强连通分量,并统计出每个强连通分量内的结点数

然后找出每个强连通分量之间的关系,也就是找出两个强连通分量之间的桥,连接可连接的强连通分量

最后将每个强连通分量收缩,得到SCC图。此时的SCC图就变成了一个DAG,所以题目就转成用DP求DAG了

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std;
#define N 1010
#define M 50010

struct Edge{
    int to, next;
}E[M];

stack<int> S;
int linklow[N], pre[N], head[N], sccno[N], num[N], dp[N];
int tot, dfs_clock, scc_cnt, n, m;
bool link[N][N];

void dfs(int u) {
    linklow[u] = pre[u] = ++dfs_clock;
    S.push(u);

    for (int i = head[u]; i != -1; i = E[i].next) {
        int v = E[i].to;
        if (!pre[v]) {
            dfs(v);
            linklow[u] = min(linklow[u], linklow[v]);
        }
        else if (!sccno[v]) {
            linklow[u] = min(linklow[u], pre[v]);
        }
    }

    if (pre[u] == linklow[u]) {
        scc_cnt++;
        num[scc_cnt] = 0;
        while (1) {
            int x = S.top();
            S.pop();
            num[scc_cnt]++;
            sccno[x] = scc_cnt;
            if (x == u)
                break;
        }
    }
}

void find_scc() {
    memset(pre, 0, sizeof(pre));
    memset(sccno, 0, sizeof(sccno));
    dfs_clock = scc_cnt = 0;

    for (int i = 0; i <= n; i++)
        if (!pre[i])
            dfs(i);
}

void AddEdge(int from, int to) {
    E[tot].to = to;
    E[tot].next = head[from];
    head[from] = tot++;
}

int DP(int u) {
    if (dp[u]) return dp[u];
    int Max = 0;
    for (int i = 1; i <= scc_cnt; i++)
        if (i != u && link[u][i])
            Max = max(Max, DP(i));
    return dp[u] = Max + num[u];
}

void init() {
    memset(head, -1, sizeof(head));
    tot = 0;

    scanf("%d%d", &n, &m);
    if (n == 0) {
        printf("0\n");
        return ;
    }
    int u, v;
    for (int i = 0; i < m; i++) {
        scanf("%d%d", &u, &v);
        AddEdge(u, v);
    }
    find_scc();
    memset(link, 0, sizeof(link));
    for (u = 0; u <= n; u++) {
        for (int i = head[u]; i != -1; i = E[i].next) {
            v = E[i].to;
            if (sccno[u] != sccno[v]) link[sccno[u]][sccno[v]] = true;
        }
    }
    memset(dp, 0, sizeof(dp));
    int Max = 0;
    for (int i = 1; i <= scc_cnt; i++) {
        Max = max(Max, DP(i));
    }
    printf("%d\n", Max);
}

int main() {
    int test;
    scanf("%d", &test);
    while (test--) {
        init();
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-26 15:56:04

UVA - 11324 The Largest Clique (DAG + 强连通分量)的相关文章

UVA 11324 - The Largest Clique(强连通分量+缩点)

UVA 11324 - The Largest Clique 题目链接 题意:给定一个有向图,要求找一个集合,使得集合内任意两点(u, v)要么u能到v,要么v能到u,问最大能选几个点 思路:强连通分量,构造出scc之后,缩点,每个点的权值是集合点个数,然后做一遍dag找出最大权值路径即可 代码: #include <cstdio> #include <cstring> #include <vector> #include <stack> #include

UVA 11324 The Largest Clique (强连通缩点 + DAG最长路)

链接 : http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=30726 题意 : 有向图G,求一个最大的点集,使得点集中任意两个节点u和v,满足 要么u可以到达v,要么v可以到达u,或者u和v可以相互到达. 可以强连通缩点成一张DAG,以为每个强连通分量要么选要么不选.求DAG上的最长路 二次建图 用了2种不同的方法,也分别用了记忆花搜索DP和直接递推DP vector建图和记忆化搜索: #include <algorithm

Uva 11324 The Largest Clique【强连通 DAG动规 spfa】

白书上的例题 做一遍tarjan后,缩点,每一个scc节点的权为它的结点数,做一次DAG上的动规,求出路径上的最大点权和,就可以了 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<stack> 6 #include<vector> 7 using namespace std; 8 9 const i

uva 11324 The Largest Clique(强连通分量缩点+DAG动态规划)

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=25&page=show_problem&problem=2299 题意:输入n和m,有n个点和m条有向边,求出一个节点集合包括的节点个数最多,而且该节点内的不论什么两点a,b,要么a能到达b,要么b能到达a,要么a和b互相到达. 思路:强连通分量缩点形成有向无环图DAG,把缩点后的每一个点的权值置为该强连通分量的节点个

UVA - 11324 The Largest Clique 强连通缩点+记忆化dp

题目要求一个最大的弱联通图. 首先对于原图进行强连通缩点,得到新图,这个新图呈链状,类似树结构. 对新图进行记忆化dp,求一条权值最长的链,每个点的权值就是当前强连通分量点的个数. /* Tarjan算法求有向图的强连通分量set记录了强连通分量 Col记录了强连通分量的个数. */ #include <iostream> #include<cstring> #include<cstdio> #include<string> #include<algo

UVA 11324 The Largest Clique (强连通分量缩点,图DP)

题目: http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=25&page=show_problem&problem=2299 题意: 给你一个有向图,求一个点集合的最大大小,使得此点集合中对于任意点对(u,v),有从u到v或者从v到u的边 方法: 先找强连通分量缩点,每个强连通分量显然满足条件,然后在缩点后的图中找到一条权值最大的路径,权值为此路径的点权之和,点权为这个

UVa 11324 The Largest Clique (强连通分量+DP)

题意:给定一个有向图,求一个最大的结点集,使得任意两个结点,要么 u 能到 v,要么 v 到u. 析:首先,如果是同一个连通分量,那么要么全选,要么全不选,然后我们就可以先把强连通分量先求出来,然后缩成一个点,然后该图就成了一个DAG,然后就可以直接用DP来做了. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #i

UVA - 11324 The Largest Clique (强连通缩点+dp)

题目链接 题意:从有向图G中找到一个最大的点集,使得该点集中任意两个结点u,v满足u可达v或v可达u. 解法:先把同处于一个强连通分量中的结点合并(缩点),得到一张DAG图,在DAG上dp即可. 感觉自己的建图写得好丑啊,一直在纠结用数组还是结构体~~ 1 #include<bits/stdc++.h> 2 3 using namespace std; 4 const int N=1e5+10; 5 int head[N],nxt[N],to[N],ne,n,m; 6 void addedge

uva 11324 The Largest Clique(图论-tarjan,动态规划)

Problem B: The Largest Clique Given a directed graph G, consider the following transformation. First, create a new graph T(G) to have the same vertex set as G. Create a directed edge between two vertices u and v in T(G) if and only if there is a path