题目链接: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. 发布tomcate时报A configuration error occurred during startup.please verify the preference field with the prompat:null

    发布tomcate时报A configuration error occurred during startup.please verify the preference field with the ...

  2. [转]使用fdisk磁盘分区和 Linux 文件系统

    概述 在本文中,学习磁盘分区和 Linux 文件系统相关内容.学习: 创建分区 使用 mkfs 命令来设置 ext2.ext3.ext4.xfs.Reiser v3 和 vfat 文件系统 创建和管理 ...

  3. SpringData JPA进阶查询—JPQL/原生SQL查询、分页处理、部分字段映射查询

    上一篇介绍了入门基础篇SpringDataJPA访问数据库.本篇介绍SpringDataJPA进一步的定制化查询,使用JPQL或者SQL进行查询.部分字段映射.分页等.本文尽量以简单的建模与代码进行展 ...

  4. 洛谷P3093 [USACO13DEC]牛奶调度Milk Scheduling

    题目描述 Farmer John has N cows that need to be milked (1 <= N <= 10,000), each of which takes onl ...

  5. BZOJ1710: [Usaco2007 Open]Cheappal 廉价回文

    len<=2000的字符串上,给出删掉和添加每种字符的花费,求把字符串变成回文串的最小花费. 首先每个字符添加和删除是一样的,因此花费在添加和删掉每个字符的花费中取小的. 如果每个字符的花费都是 ...

  6. OC-runtime 的温习

    -.runtime简介 runtime简称运行时,OC就是运行时机制,也就是运行时的一些机制,其中最主要的是消息机制: 对于C语言,函数的调用在编辑的时候,会决定调用哪个函数: 对于OC的函数,属于动 ...

  7. ubuntu-12.04下安装postgresql

    2013-10-01 20:42:57|    moniter参考资料:Ubuntu 12.04下PostgreSQL-9.1安装与配置详解(在线安装)一.安装postgresqlbamboo@bam ...

  8. loj6172 Samjia和大树(树形DP+找规律)

    题目: https://loj.ac/problem/6172 分析: 首先容易得出这样的dp式子 然后发现后面那个Σ其实是两段区间,可以用总和减去中间一段区间表示,所以只要维护个前缀和就ok了 这样 ...

  9. DATASNAP高效的FIREDAC数据序列和还原

    变量定义: varFDConnection: TFDConnection;qCustomers: TFDQuery; qOrders: TFDQuery;FDSchemaAdapter: TFDSch ...

  10. 使用datatables实现后台分页功能,减轻前端渲染压力

    注意不同版本,参数名字及参数内容存在差异,具体可以参考https://datatables.net/upgrade/1.10-convert#Options 控制页面显示的参数:https://dat ...