您的位置:首页 > 其它

Uva 11324 强连通分量求解 + 缩点——有向无环图求最长路径

2014-06-29 16:53 357 查看
http://vjudge.net/contest/view.action?cid=48251#problem/E


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

题目大意:给一张有向图G,求一个节点数最大的节点集,使得该点集中,任意两个节点u和v满足:要么u可以到达v,要么v可以到达u(u和v相互到达也可以);
解题思路:不难发现在最优的方案中,同一个强连通分量中的点要么都选,要么都不选。把强连通分量搜索点后得到一个无环图,每一个节点的权等于它的节点数,则题目转化为求该无环图上权最大的路径。可用动态规划求解。

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stack>
using namespace std;
const int N=1002;
const int M=50005;
struct note
{
int u;
int v;
int next;
} edge[M],a[M];
int head
,ip,in
,Q
,dfn
,low
,sccno
,dp
;
bool _map

;
int n,m,stamp,cnt_edge,scc_cnt,top,scc_val
;
stack <int> q;
void addedge(int u,int v)
{
edge[ip].v=v;
edge[ip].next=head[u];
head[u]=ip++;
}
void init()
{
scc_cnt=0;
stamp=0;
memset(in,0,sizeof(in));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(scc_val,0,sizeof(scc_val));
memset(_map,0,sizeof(_map));
memset(dp,0,sizeof(dp));
memset(sccno,0,sizeof(sccno));
memset(head,-1,sizeof(head));
ip=0;
}
void tarjan(int u)
{
dfn[u]=low[u]=++stamp;
q.push(u);
for(int i=head[u]; i!=-1; i=edge[i].next)
{
int v=edge[i].v;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(!scc_val[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
scc_cnt++;
int x;
do
{
x=q.top();
q.pop();
scc_val[x]=scc_cnt;
sccno[scc_cnt]++;
}
while(x!=u);
}
}
void DP()
{
int car=0,cdr=0;
/*for(int i=1;i<=scc_cnt;i++)
printf("(%d %d)\n",in[i],sccno[i]);*/
for(int i=1; i<=scc_cnt; i++)
{
if(in[i]==0)
Q[car++]=i,dp[i]=sccno[i];
}
while(car!=cdr)
{
int u=Q[cdr++];
for(int k=head[u]; k!=-1; k=edge[k].next)
{
int v=edge[k].v;
dp[v]=max(dp[v],dp[u]+sccno[v]);
if(--in[v]==0)
Q[car++]=v;
}
}
}
int main()
{
int T,u,v;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
init();
for(int i=0; i<m; i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
a[i].u=u,a[i].v=v;
}
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
memset(head,-1,sizeof(head));
ip=0;
for(int i=0; i<m; i++)
{
u=a[i].u,v=a[i].v;
if(scc_val[u]!=scc_val[v]&&!_map[scc_val[u]][scc_val[v]])
{
addedge(scc_val[u],scc_val[v]);
in[scc_val[v]]++;
_map[scc_val[u]][scc_val[v]]=true;
}
}
DP();
int ans = 0;
for (int i = 1; i <= scc_cnt; i++) ans = max(ans, dp[i]);
printf("%d\n", ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: