题目链接:https://vjudge.net/problem/UVA-11324

题解:

题意:给出一张有向图,求一个结点数最大的结点集,使得任意两个结点u、v,要么u能到达v, 要么v能到达u(u和v也可以互相到达)。

1.可知在一个强连通分量中,任意两个点都可以互相到达。那么我们就对每个强连通分量进行缩点,并记录每个分量的结点个数。

2.缩点之后,就是一张有向无环图了,这时就转化为求:从有向无环图中找出一条权值之和最大的路径。简单的记忆化搜索即可实现。

前向星建图 + 前向星重建:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const double EPS = 1e-;
const int INF = 2e9;
const LL LNF = 2e18;
const int MAXM = 5e4+;
const int MAXN = 1e3+; struct Edge
{
int to, next;
}edge[MAXM], edge0[MAXM]; //edge为初始图, edge0为重建图
int tot, head[MAXN], tot0, head0[MAXN]; int Index, dfn[MAXN], low[MAXN];
int top, Stack[MAXN], instack[MAXN];
int scc, belong[MAXN], num[MAXN];
int dp[MAXN]; void addedge(int u, int v, Edge edge[], int head[], int &tot)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
} void Tarjan(int u)
{
dfn[u] = low[u] = ++Index;
Stack[top++] = u;
instack[u] = true;
for(int i = head[u]; i!=-; i = edge[i].next)
{
int v = edge[i].to;
if(!dfn[v])
{
Tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(instack[v])
low[u] = min(low[u], dfn[v]);
} if(dfn[u]==low[u])
{
int v;
scc++;
do
{
v = Stack[--top];
instack[v] = false;
belong[v] = scc;
num[scc]++;
}while(v!=u);
}
} int dfs(int u)
{
if(dp[u]!=-) return dp[u];
dp[u] = num[u];
for(int i = head0[u]; i!=-; i = edge0[i].next)
{
int v = edge0[i].to;
dp[u] = max(dp[u], num[u]+dfs(v));
}
return dp[u];
} void init()
{
tot = tot0 = ;
memset(head, -, sizeof(head));
memset(head0, -, sizeof(head0)); Index = top = ;
memset(dfn, , sizeof(dfn));
memset(low, , sizeof(low));
memset(instack, , sizeof(instack)); scc = ;
memset(num, , sizeof(num));
memset(dp, -, sizeof(dp));
} int main()
{
int n, m, T;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
init();
for(int i = ; i<=m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
addedge(u, v, edge, head, tot);
} for(int i = ; i<=n; i++)
if(!dfn[i])
Tarjan(i); for(int u = ; u<=n; u++) //重建建图
for(int i = head[u]; i!=-; i = edge[i].next)
{
int tmpu = belong[u];
int tmpv = belong[edge[i].to];
if(tmpu!=tmpv)
addedge(tmpu, tmpv, edge0, head0, tot0);
} int ans = ;
for(int i = ; i<=scc; i++)
if(dp[i]==-)
ans = max(ans, dfs(i)); printf("%d\n", ans);
}
}

前向星建图 + vector重建:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const double EPS = 1e-;
const int INF = 2e9;
const int MAXM = 5e4+;
const int MAXN = 1e3+; struct Edge
{
int to, next;
}edge[MAXM];
int tot, head[MAXN];
vector<int>g[MAXN]; int Index, dfn[MAXN], low[MAXN];
int top, Stack[MAXN], instack[MAXN];
int scc, belong[MAXN], num[MAXN];
int dp[MAXN]; void addedge(int u, int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
} void Tarjan(int u)
{
dfn[u] = low[u] = ++Index;
Stack[top++] = u;
instack[u] = true;
for(int i = head[u]; i!=-; i = edge[i].next)
{
int v = edge[i].to;
if(!dfn[v])
{
Tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(instack[v])
low[u] = min(low[u], dfn[v]);
} if(dfn[u]==low[u])
{
int v;
scc++;
do
{
v = Stack[--top];
instack[v] = false;
belong[v] = scc;
num[scc]++;
}while(v!=u);
}
} int dfs(int u)
{
if(dp[u]!=-) return dp[u];
dp[u] = num[u];
for(int i = ; i<g[u].size(); i++)
{
int v = g[u][i];
dp[u] = max(dp[u], num[u]+dfs(v));
}
return dp[u];
} void init(int n)
{
tot = ;
memset(head, -, sizeof(head)); Index = top = ;
memset(dfn, , sizeof(dfn));
memset(low, , sizeof(low));
memset(instack, , sizeof(instack)); scc = ;
memset(num, , sizeof(num));
memset(dp, -, sizeof(dp));
for(int i = ; i<=n; i++)
g[i].clear();
} int main()
{
int n, m, T;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
init(n);
for(int i = ; i<=m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
addedge(u, v);
} for(int i = ; i<=n; i++)
if(!dfn[i])
Tarjan(i); for(int u = ; u<=n; u++)
for(int i = head[u]; i!=-; i = edge[i].next)
{
int tmpu = belong[u];
int tmpv = belong[edge[i].to];
if(tmpu!=tmpv)
g[tmpu].push_back(tmpv);
} int ans = ;
for(int i = ; i<=scc; i++)
if(dp[i]==-)
ans = max(ans, dfs(i)); printf("%d\n", ans);
}
}

vector建图 + vector重建:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const double EPS = 1e-;
const int INF = 2e9;
const int MAXN = 1e3+; vector<int>G[MAXN], g[MAXN]; int Index, dfn[MAXN], low[MAXN];
int top, Stack[MAXN], instack[MAXN];
int scc, belong[MAXN], num[MAXN];
int dp[MAXN]; void Tarjan(int u)
{
dfn[u] = low[u] = ++Index;
Stack[top++] = u;
instack[u] = true;
for(int i = ; i<G[u].size(); i++)
{
int v = G[u][i];
if(!dfn[v])
{
Tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(instack[v])
low[u] = min(low[u], dfn[v]);
} if(dfn[u]==low[u])
{
int v;
scc++;
do
{
v = Stack[--top];
instack[v] = false;
belong[v] = scc;
num[scc]++;
}while(v!=u);
}
} int dfs(int u)
{
if(dp[u]!=-) return dp[u];
dp[u] = num[u];
for(int i = ; i<g[u].size(); i++)
{
int v = g[u][i];
dp[u] = max(dp[u], num[u]+dfs(v));
}
return dp[u];
} void init(int n)
{
Index = top = ;
memset(dfn, , sizeof(dfn));
memset(low, , sizeof(low));
memset(instack, , sizeof(instack)); scc = ;
memset(num, , sizeof(num));
memset(dp, -, sizeof(dp));
for(int i = ; i<=n; i++)
{
G[i].clear();
g[i].clear();
}
} int main()
{
int n, m, T;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
init(n);
for(int i = ; i<=m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
} for(int i = ; i<=n; i++)
if(!dfn[i])
Tarjan(i); for(int u = ; u<=n; u++)
for(int i = ; i<G[u].size(); i++)
{
int tmpu = belong[u];
int tmpv = belong[G[u][i]];
if(tmpu!=tmpv)
g[tmpu].push_back(tmpv);
} int ans = ;
for(int i = ; i<=scc; i++)
if(dp[i]==-)
ans = max(ans, dfs(i)); printf("%d\n", ans);
}
}

UVA11324 The Largest Clique —— 强连通分量 + 缩点 + DP的更多相关文章

  1. UVA11324 The Largest Clique[强连通分量 缩点 DP]

    UVA - 11324 The Largest Clique 题意:求一个节点数最大的节点集,使任意两个节点至少从一个可以到另一个 同一个SCC要选一定全选 求SCC 缩点建一个新图得到一个DAG,直 ...

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

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=25&page=sh ...

  3. UVA 11324 The Largest Clique(强连通分量+缩点DAG的DP)

    题意:给定一个有向图,求出一个最大的结点集,这个节点集中的随意两个点之间至少一个能到达还有一个点. 思路:假设一个点在这个节点集中,那么它所在的强连通分量中的点一定所有在这个节点集中,反之亦然, 求出 ...

  4. UVA11324 The Largest Clique (强连通缩点+DP最长路)

    <题目链接> 题目大意: 给你一张有向图 G,求一个结点数最大的结点集,使得该结点集中的任意两个结点 u 和 v 满足:要么 u 可以达 v,要么 v 可以达 u(u,v相互可达也行). ...

  5. uva11324 The Largest Clique --- 强连通+dp

    给一个有向图G,求一个子图要求当中随意两点至少有一边可达. 问这个子图中最多含多少个顶点. 首先找SCC缩点建图.每一个点的权值就是该点包括点的个数. 要求当中随意两点可达,实际上全部边仅仅能同方向, ...

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

    题意:给定一个有向图,求一个最大的结点集,使得任意两个结点,要么 u 能到 v,要么 v 到u. 析:首先,如果是同一个连通分量,那么要么全选,要么全不选,然后我们就可以先把强连通分量先求出来,然后缩 ...

  7. BZOJ 1179 Atm(强连通分量缩点+DP)

    题目说可以通过一条边多次,且点权是非负的,所以如果走到图中的一个强连通分量,那么一定可以拿完这个强连通分量上的money. 所以缩点已经很明显了.缩完点之后图就是一个DAG,对于DAG可以用DP来求出 ...

  8. POJ3160 Father Christmas flymouse[强连通分量 缩点 DP]

    Father Christmas flymouse Time Limit: 1000MS   Memory Limit: 131072K Total Submissions: 3241   Accep ...

  9. UVa11324 The Largest Clique(强连通分量+缩点+记忆化搜索)

    题目给一张有向图G,要在其传递闭包T(G)上删除若干点,使得留下来的所有点具有单连通性,问最多能留下几个点. 其实这道题在T(G)上的连通性等同于在G上的连通性,所以考虑G就行了. 那么问题就简单了, ...

随机推荐

  1. oracle中的权限管理

    connect resource权限 grant connect,resource to user; 执行上面的sql语句后用户包括的权限: CONNECT角色: --是授予最终用户的典型权利,最基本 ...

  2. Java基础学习总结(94)——Java线程再学习

    Java线程有哪些不太为人所知的技巧与用法? 萝卜白菜各有所爱.像我就喜欢Java.学无止境,这也是我喜欢它的一个原因.日常工作中你所用到的工具,通常都有些你从来没有了解过的东西,比方说某个方法或者是 ...

  3. PTA 05-树8 File Transfer (25分)

    题目地址 https://pta.patest.cn/pta/test/16/exam/4/question/670 5-8 File Transfer   (25分) We have a netwo ...

  4. python学习笔记--python简介

    一.什么是python? python是一种面向对象.解释型的高级程序语言.python具有语法简洁.易于学习.功能强大,可扩展性强,跨平台等诸多特点.1989年开始开发,于1991年发布第一个公开发 ...

  5. js中trim函数的简单实现

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...

  6. [Usaco2007 Oct] Super Paintball超级弹珠

    Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 489  Solved: 384[Submit][Status][Discuss] Description ...

  7. 转 蓝桥杯 历届试题 大臣的旅费 [ dfs 树的直径 ]

    题解: 求树的直径. 转一篇博客:http://www.cnblogs.com/hanyulcf/archive/2010/10/23/tree_radius.html 树的直径是指树的最长简单路.求 ...

  8. PB编译

    java -jar wire-compiler-1.8.0-jar-with-dependencies.jar --java_out=./  ngame.proto 其中java_out是指输出要放在 ...

  9. Windows下SVN服务器及客户端的使用

    原文地址:windows下配置VisualSVN Server服务器 作者:Deem_passion 下载安装文件: 服务端安装文件:VisualSVN-Server-1.6.2 客户端安装文件:To ...

  10. jenkins修改日志级别方法

    1.jenkins日志有时候也会消耗掉很大内存,在传输时也会消耗掉大量带宽,如图,300+M的日志大小,太夸张了吧 2.修改日志级别的方法: 在配置文件里修改,重启后永久生效,配置路径:/etc/sy ...