UVA 11324 Problem B: The Largest Clique(强连通+DP,4级)

Problem B: The Largest Clique

Given a directed graph G, consider the following transformation. First, create a new graph T(G) to have the same vertex set as G. Create a directed edge between two vertices u and v in T(G) if and only if there is a path between u and v in G that follows the directed edges only in the forward direction. This graph T(G) is often called the transitive closure of G.

We define a clique in a directed graph as a set of vertices U such that for any two vertices u and v in U, there is a directed edge either from u to v or from v to u (or both). The size of a clique is the number of vertices in the clique.

The number of cases is given on the first line of input. Each test case describes a graph G. It begins with a line of two integers n and m, where 0 ≤ n ≤ 1000 is the number of vertices of G and 0 ≤ m ≤ 50,000 is the number of directed edges of G. The vertices of G are numbered from 1 to n. The following m lines contain two distinct integers u and v between 1 and n which define a directed edge from u tov in G.

For each test case, output a single integer that is the size of the largest clique in T(G).

Sample input

1
5 5
1 2
2 3
3 1
4 1
5 2

Output for sample input

4

Zachary Friggstad


思路:强连通缩点后,个缩后的点一个权值,就是当前点包含点的个数,然后搜条权值最大的路径就是个水DP了。


159MS

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int mm=1000+9;
const int mn=5e4+9;
int head[mm],edge;
class node
{
  public:int v,next;
}e[mn],cun[mn];
int m,n;
void add(int u,int v)
{
  e[edge].v=v;e[edge].next=head[u];head[u]=edge++;
}
void data()
{
  memset(head,-1,sizeof(head));edge=0;
}
int bcc_no,dfs_clock,e_to[mm],dfn[mm];
int stak[mm],top,cost[mm];
int tarjan(int u)
{ stak[++top]=u;
  int lowv,lowu,v;
  dfn[u]=lowu=++dfs_clock;
  for(int i=head[u];~i;i=e[i].next)
  {v=e[i].v;
    if(!dfn[v])
    {
      lowv=tarjan(v);
      lowu=min(lowu,lowv);
    }
    else if(!e_to[v])
      lowu=min(dfn[v],lowu);
  }
  if(dfn[u]==lowu)
  {
    bcc_no++;int num=0;
    while(1)
    { ++num;
      v=stak[top--];e_to[v]=bcc_no;
      if(v==u)break;
    }
    cost[bcc_no]=num;
  }
  return lowu;
}
void find_gcc()
{
  memset(dfn,0,sizeof(dfn));
  memset(e_to,0,sizeof(e_to));
  bcc_no=top=dfs_clock=0;
  for(int i=1;i<=n;++i)
    if(!dfn[i])tarjan(i);
}
int dp[mm];
int dfs(int u)
{ int v;
  if(dp[u])return dp[u];
  for(int i=head[u];~i;i=e[i].next)
  {
    v=e[i].v;
    dp[u]=max(dp[u],dfs(v));
  }
  dp[u]+=cost[u];
  return dp[u];
}
int solve()
{
  data();int u,v;
  for(int i=0;i<m;++i)
  {
    u=e_to[cun[i].next];v=e_to[cun[i].v];
    if(u^v)
    {
      add(u,v);
    }
  }
  int ans=0;
  memset(dp,0,sizeof(dp));
  for(int i=1;i<=bcc_no;++i)
    {ans=max(ans,dfs(i));
     ///cout<<i<<" "<<dp[i]<<endl;
    }
    return ans;
}
int main()
{
  int cas,a,b;
  while(~scanf("%d",&cas))
  {
    while(cas--)
    { data();
      scanf("%d%d",&n,&m);
      for(int i=0;i<m;++i)
      {
        scanf("%d%d",&a,&b);
        cun[i].next=a;cun[i].v=b;
        if(a==b)continue;
        add(a,b);
      }
      find_gcc();
      int ans=solve();
      if(n==0)ans=0;
      printf("%d\n",ans);
    }
  }
  return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值