UVA11324 The Largest Clique —— 强连通分量 + 缩点 + DP
题目链接: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的更多相关文章
- UVA11324 The Largest Clique[强连通分量 缩点 DP]
UVA - 11324 The Largest Clique 题意:求一个节点数最大的节点集,使任意两个节点至少从一个可以到另一个 同一个SCC要选一定全选 求SCC 缩点建一个新图得到一个DAG,直 ...
- uva 11324 The Largest Clique(强连通分量缩点+DAG动态规划)
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=25&page=sh ...
- UVA 11324 The Largest Clique(强连通分量+缩点DAG的DP)
题意:给定一个有向图,求出一个最大的结点集,这个节点集中的随意两个点之间至少一个能到达还有一个点. 思路:假设一个点在这个节点集中,那么它所在的强连通分量中的点一定所有在这个节点集中,反之亦然, 求出 ...
- UVA11324 The Largest Clique (强连通缩点+DP最长路)
<题目链接> 题目大意: 给你一张有向图 G,求一个结点数最大的结点集,使得该结点集中的任意两个结点 u 和 v 满足:要么 u 可以达 v,要么 v 可以达 u(u,v相互可达也行). ...
- uva11324 The Largest Clique --- 强连通+dp
给一个有向图G,求一个子图要求当中随意两点至少有一边可达. 问这个子图中最多含多少个顶点. 首先找SCC缩点建图.每一个点的权值就是该点包括点的个数. 要求当中随意两点可达,实际上全部边仅仅能同方向, ...
- UVa 11324 The Largest Clique (强连通分量+DP)
题意:给定一个有向图,求一个最大的结点集,使得任意两个结点,要么 u 能到 v,要么 v 到u. 析:首先,如果是同一个连通分量,那么要么全选,要么全不选,然后我们就可以先把强连通分量先求出来,然后缩 ...
- BZOJ 1179 Atm(强连通分量缩点+DP)
题目说可以通过一条边多次,且点权是非负的,所以如果走到图中的一个强连通分量,那么一定可以拿完这个强连通分量上的money. 所以缩点已经很明显了.缩完点之后图就是一个DAG,对于DAG可以用DP来求出 ...
- POJ3160 Father Christmas flymouse[强连通分量 缩点 DP]
Father Christmas flymouse Time Limit: 1000MS Memory Limit: 131072K Total Submissions: 3241 Accep ...
- UVa11324 The Largest Clique(强连通分量+缩点+记忆化搜索)
题目给一张有向图G,要在其传递闭包T(G)上删除若干点,使得留下来的所有点具有单连通性,问最多能留下几个点. 其实这道题在T(G)上的连通性等同于在G上的连通性,所以考虑G就行了. 那么问题就简单了, ...
随机推荐
- 利用OpenXml读取、导出Excel
OpenXml是通过 XML 文档提供行集视图.由于OPENXML 是行集提供程序,因此可在会出现行集提供程序(如表.视图或 OPENROWSET 函数)的 Transact-SQL 语句中使用 OP ...
- xtu read problem training A - Dividing
A - Dividing Time Limit:1000MS Memory Limit:10000KB 64bit IO Format:%I64d & %I64u Descri ...
- Leetcode 273.整数转换英文表示
整数转换英文表示 将非负整数转换为其对应的英文表示.可以保证给定输入小于 231 - 1 . 示例 1: 输入: 123 输出: "One Hundred Twenty Three" ...
- Laya Tween 和 遮罩
Laya Tween 和 遮罩 @author ixenos 场景:在使用Tween循环时,不规则物体部分超出范围 方案:使用遮罩定型 困境:在laya ide设计模式中将遮罩sprite放到不规则物 ...
- JavaEE JDBC 了解数据库连接池
了解数据库连接池 @author ixenos 数据库连接是有限的资源,如果用户需要离开应用一段时间,那么他占用的连接就不应该保持开放状态: 另一方面,每次查询都获取连接并在随后关闭它的代价也很高. ...
- poj 2081 简单递推
#include<stdio.h> #include<string.h> #define N 510000 int dp[N]; int f[10000000]; int ma ...
- github新建本地仓库,再同步远程仓库基本用法
github新建本地仓库,再同步远程仓库基本用法 1 mkdir gitRepo 2 cd gitRepo 3 git init #初始化本地仓库 4 git add xxx #添加要push到远 ...
- msp430项目编程10
msp430中项目---电子密码锁 1.扫描键盘工作原理 2.电路原理说明 3.代码(显示部分) 4.代码(功能实现) 5.项目总结 msp430项目编程 msp430入门学习
- 通过分析system_call中断处理过程来深入理解系统调用
通过分析system_call中断处理过程来深入理解系统调用 前言说明 本篇为网易云课堂Linux内核分析课程的第五周作业,上一次作业中我以2个系统调用(getpid, open)作为分析实例来分析系 ...
- Flex的Combobox组件使用技巧
1.显示提示设置Prompt属性可以为Combobox添加一个默认提示.如果没有设置selectedIndex,默认selectedIndex=-1,就显示Prompt的内容.Flex3如果不设置Pr ...