您的位置:首页 > 产品设计 > UI/UE

UVA11324_The Largest Clique_tarjan求强连通分量+DP求最长路

2013-07-21 22:19 369 查看
题意:

给一个图,求它的一个最大子图,使得图中任意两点之间都至少有一条路径【注意是两点之间有路径,而不是可以到达任意一点,所以不是强连通分量】

【PS:题中给的传递闭包其实是个迷惑,没有用,因为在原图上做,和在传递闭包的图上做是完全一样的】

题解:

先求出图中的所有强连通分量,将每个分量缩为一点使之成为一个DAG图,这样在这个无环图中,找子图使得满足条件

关键:

把问题“使得子图中任意两点之间都至少有一条路径”转化成“求一条最长路径”

这个非常关键,反正我刚开始挺难想的,不过推一推确实是这样,由于任意两点之间都有路,所以所有的路都可以压缩到同一条路径上,如果不能压缩,说明这个子图一定存在两点之间没有有向路径

而求最长路的问题又可以用DP来做,状态转移方程为 dp[u]=val[u]+max(dp[v])

其中,v是u的全部子节点,val[u]为当前标号为u的强连通分量中的结点个数,这样就可以求出来最大子图了

原题:

Problem B: The Largest Clique

Given a directed graph G, consider the following transformation. First, create a new graphT(G) to have the same vertex set as G. Create a directed edge betweentwo vertices u and v in T(G) if and only if there is a pathbetween
u and v in G that follows the directed edges only in the forwarddirection. 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 thatfor any two vertices u and v in U, there is a directededge 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 integersn and m, where 0 ≤ n ≤ 1000 is the number ofvertices of Gand 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 vbetween 1 and n which definea directed edge from u to v 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
41
5 2

Output for sample input

4


代码:

RunIDUserProblemResultMemoryTimeLanguageLengthSubmit Time
1321499chengtbfAAccepted0 KB152 msC++ 4.5.32550 B2013-07-21 21:58:40
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#define N 1005
#define M 50005
using namespace std;

int dfs_time;
int dfn
,low
;
int color
;
int dfs_color;
int n,m;
struct MyStruct
{
int u,v;
}edge[M];
vector<int>f
;
vector<int>DAG
;//存缩点后的图
stack<int>sta;
int visited
;
int in_stack
;//判断是否在栈中
int dp
;
int val
;//即每个强连通分量中的结点个数
int vis_DAG
;//标记DAG图中的缩点有没有被访问过

int find_min(int a,int b)
{
return a<b?a:b;
}
void tarjan(int u)
{
dfn[u]=low[u]=++dfs_time;
visited[u]=1;
sta.push(u);
in_stack[u]=1;
int child;
for (int i = 0; i <f[u].size() ; i++)
{
child=f[u][i];
if (!visited[child])
{
tarjan(child);
low[u]=find_min(low[u],low[child]);
}
else if(in_stack[child])
{
low[u]=find_min(low[u],dfn[child]);
}
}
if (dfn[u]==low[u])//说明u是当前连通分量的根
{
dfs_color++;
do//弹出当前强连通分量
{
child=sta.top();
color[child]=dfs_color;
sta.pop();
in_stack[child]=0;
val[dfs_color]++;

} while (u!=child);
}
}

void dp_DAG(int u)//这里的u是强连通分量的缩点的标号
{
vis_DAG[u]=1;
int max=0;
int child;
for (int i = 0; i < DAG[u].size(); i++)
{
child=DAG[u][i];
if (!vis_DAG[child])
{
dp_DAG(child);

}
if (max<dp[child])
{
max=dp[child];
}
}
dp[u]=val[u]+max;//如果dfs搜到叶子结点,就直接到这一步,此时max=0,恰好满足dp[u]=val[u]
}

int main()
{
int i,j,a,b,t;
int point_u,point_v;
int ans;
scanf("%d",&t);
while (t--)
{
scanf("%d%d",&n,&m);
for ( i = 0; i <=n ; i++)
{
f[i].clear();
DAG[i].clear();
}
if (!sta.empty())
{
sta.pop();
}
memset(visited,0,sizeof(visited));
memset(val,0,sizeof(val));
memset(in_stack,0,sizeof(in_stack));
memset(dp,0,sizeof(dp));
memset(vis_DAG,0,sizeof(vis_DAG));
dfs_time=0;
dfs_color=0;
ans=0;

for ( i = 1; i <=m ; i++)//输入,存边,存图
{
scanf("%d%d",&a,&b);
edge[i].u=a;
edge[i].v=b;
f[a].push_back(b);
}
for ( i = 1; i <=n ; i++)//求强连通分量
{
if (!visited[i])
{
tarjan(i);
}
}
for ( i = 1; i <=m ; i++)//存DAG图
{
point_u=color[edge[i].u];
point_v=color[edge[i].v];
DAG[point_u].push_back(point_v);
}
for ( i = 1; i <=dfs_color ; i++)
{
if (!vis_DAG[i])
{
dp_DAG(i);
}
}
for ( i = 1; i <=dfs_color; i++)
{
if (dp[i]>ans)
{
ans=dp[i];
}
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: