UVa 11324 The Largest Clique (强连通分量,dp)

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

题意:给一张有向图G,求一个节点数最大的结点集,使得该结点集中任意两个结点u和v满足:要么u可以到达v,要么v可以到达u(或者u和v相互可达)

思路:首先求出图的强连通分量,并把其收缩点得到scc图,每个scc结点权值为它的节点数。则问题转化成了,给出一个DAG图,各点权值已知,求一条权值最大的路径。可以用dp进行求解。


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fin(a) freopen("a.txt","r",stdin)
#define fout(a) freopen("a.txt","w",stdout)
using namespace std;
const int maxn = 1000 + 10;
stack S;
vector G[maxn], G2[maxn];
int n, m;
int con[maxn][maxn], dp[maxn], sccno[maxn], pre[maxn], low[maxn], val[maxn], scc_cnt, scc_clock;

void input_Edge() {
  scanf("%d%d", &n, &m);
  for(int i = 1; i <= n; i++) G[i].clear();
  for(int i = 1; i <= m; i++) {
    int x, y;
    scanf("%d%d", &x, &y);
    G[x].push_back(y);
  }
}

void dfs(int u) {
  pre[u] = low[u] = ++scc_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;
    for(;;) {
      int x = S.top(); S.pop();
      sccno[x] = scc_cnt;
      val[scc_cnt]++;
      if(x == u) break;
    }
  }
}

void get_scc() {
  while(!S.empty()) S.pop();
  memset(sccno, 0, sizeof sccno);
  memset(pre, 0, sizeof pre);
  memset(low, 0, sizeof low);
  memset(val, 0, sizeof val);
  scc_cnt = scc_clock = 0;
  for(int i = 1; i <= n; i++)
    if(!pre[i]) dfs(i);
}

void get_new() {
  memset(con, 0, sizeof con);
  for(int i = 1; i <= n; i++) G2[i].clear();
  for(int u = 1; u <= n; u++)
    for(int i = 0; i < G[u].size(); i++) {
      int v = G[u][i];
      int a = sccno[u], b = sccno[v];
      if(a == b || con[a][b]) continue;
      con[a][b] = 1;
      G2[a].push_back(b);
    }
}

int d(int u) {
  if(G2[u].size() == 0) return val[u];
  int& ans = dp[u];
  if(ans > 0) return ans;
  for(int i = 0; i < G2[u].size(); i++)
    ans = max(ans, val[u] + d(G2[u][i]));
  return ans;
}

int solve() {
  memset(dp, 0, sizeof dp);
  int ans = 0;
  for(int i = 1; i <= scc_cnt; i++)
    ans = max(ans, d(i));
  return ans;
}

int main() {
  int T;
  scanf("%d", &T);
  while(T--) {
    input_Edge();
    get_scc();
    get_new();
    printf("%d\n", solve());
  }
  return 0;
}


你可能感兴趣的:(UVa,图论)