UVA-11324 The Largest Clique
题目
给定一张有向图G,求一个节点数目最大的节点集,使得该集合中的任意两个节点u和v满足:要么u可以到达v,要么v可以到达u(u,v相互可达也算满足),要求输出最大的节点数
分析
在强连通子图里,任何两个点两两可达,先求图中所有强连通分量,缩点,之后每个缩点组成了一张
图,那么问题就转变成了求
代码
#include <bits/stdc++.h>
using namespace std;
#define d(x) cout<<(x)<<endl
const int N = 1e3 + 10;
int _, n, m;
vector<int> g[N];
int pre[N], low[N], sccno[N], dfs_clock, scc_cnt;
stack<int> s;
void dfs(int u){
pre[u] = low[u] = ++dfs_clock;
s.push(u);
for (int i = 0; i < g[u].size(); i++)
{
int v = g[u][i];
if(!pre[v]){
dfs(v);
low[u] = min(low[u], low[v]);
}else if(!sccno[v])
low[u] = min(low[u], pre[v]);
}
if(low[u] == pre[u]){
scc_cnt++;
while(1){
int x = s.top();
s.pop();
sccno[x] = scc_cnt;
if(x == u)
break;
}
}
}
void find_scc(){
dfs_clock = scc_cnt = 0;
memset(sccno, 0, sizeof sccno);
memset(pre, 0, sizeof pre);
for(int i = 1; i <= n; i++)
if(!pre[i])
dfs(i);
}
int size[N], e[N][N], dp[N];
int DP(int u){
int &ans = dp[u];
if(ans >= 0)
return ans;
ans = size[u]; // 当前节点权值
for(int v = 1; v <= scc_cnt; v++){ // 遍历 u 所有子节点
if(u != v && e[u][v])
ans = max(ans, DP(v) + size[u]);
}
return ans;
}
int main()
{
for (scanf("%d", &_); _; _--){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
g[i].clear();
for(int i = 0, u, v; i < m; i++){
scanf("%d%d", &u, &v);
g[u].push_back(v);
}
find_scc(); // 找强连通分量
memset(size, 0, sizeof size);
memset(e, 0, sizeof e);
for(int i = 1; i <= n; i++){
size[sccno[i]]++; // 求DAG上每个点权值
for (int j = 0; j < g[i].size(); j++)
e[sccno[i]][sccno[g[i][j]]] = 1;
// 构造 SCC 图
}
int ans = 0;
memset(dp, -1, sizeof dp);
// 从每个点开始
for(int i = 1; i <= scc_cnt; i++){
ans = max(ans, DP(i)); // 1 ~~ scc_cnt
}
printf("%d\n", ans);
}
return 0;
}
用邻接表写就错。。。
#include <bits/stdc++.h>
using namespace std;
#define d(x) cout<<(x)<<endl
const int N = 1e3 + 10;
int _, n, m;
int h[N], to[N], ne[N], idx;
int pre[N], low[N], sccno[N], dfs_clock, scc_cnt;
stack<int> s;
inline void add(int a, int b){
to[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u){
pre[u] = low[u] = ++dfs_clock;
s.push(u);
for(int i = h[u]; ~i; i = ne[i]){
int v = to[i];
if(!pre[v]){
dfs(v);
low[u] = min(low[u], low[v]);
}else if(!sccno[v])
low[u] = min(low[u], pre[v]);
}
if(low[u] == pre[u]){
scc_cnt++;
while(1){
int x = s.top();
s.pop();
sccno[x] = scc_cnt;
if(x == u)
break;
}
}
}
void find_scc(){
dfs_clock = scc_cnt = 0;
memset(sccno, 0, sizeof sccno);
memset(pre, 0, sizeof pre);
for(int i = 1; i <= n; i++)
if(!pre[i])
dfs(i);
}
int size[N], e[N][N], dp[N];
int DP(int u){
int &ans = dp[u];
if(ans >= 0)
return ans;
ans = size[u]; // 当前节点权值
for(int v = 1; v <= scc_cnt; v++){ // 遍历 u 所有子节点
if(u != v && e[u][v])
ans = max(ans, DP(v) + size[u]);
}
return ans;
}
int main()
{
for (scanf("%d", &_); _; _--){
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
while(!s.empty())
s.pop();
idx = 0;
for(int i = 0, u, v; i < m; i++){
scanf("%d%d", &u, &v);
// u--, v--;
add(u, v);
}
find_scc(); // 找强连通分量
memset(size, 0, sizeof size);
memset(e, 0, sizeof e);
for(int i = 1; i <= n; i++){
size[sccno[i]]++; // 求DAG上每个点权值
for (int j = h[i]; ~j; j = ne[j])
e[sccno[i]][sccno[to[j]]] = 1;
// 构造 SCC 图
}
int ans = 0;
memset(dp, -1, sizeof dp);
// 从每个点开始
for(int i = 1; i <= scc_cnt; i++){
ans = max(ans, DP(i)); // 1 ~~ scc_cnt
// cout << ans << endl;
}
printf("%d\n", ans);
}
return 0;
}