P3916 图的遍历(缩点+记忆化搜索)

题目描述

给出N个点,M条边的有向图,对于每个点v,求A(v)表示从点v出发,能到达的编号最大的点。
输入格式

第1 行,2 个整数N,M。

接下来M行,每行2个整数Ui​,Vi​,表示边(Ui​,Vi​)。点用1,2,⋯,N编号。
输出格式

N 个整数A(1),A(2),⋯,A(N)。
输入输出样例
输入 #1

4 3
1 2
2 4
4 3

输出 #1

4 4 3 4

说明/提示

• 对于60% 的数据,1≤N.K≤1031 \le N . K \le 10^31≤N.K≤103;

• 对于100% 的数据,1≤N,M≤1051 \le N , M \le 10^51≤N,M≤105。

这个题不缩点也是可以过的,但是既然想到了就顺手写了一个,然后就对tarjan有了更深的理解,也算是写有所得了…

//正确的代码
	if(dfn[v]==0)
	{
		tarjan(v);
		low[u]=min(low[u],low[v]);
	}
	else if(vis[v])
		low[u]=min(low[u],dfn[v]);
//错误的代码
	if(dfn[v]==0)
	{
		tarjan(v);
		low[u]=min(low[u],low[v]);
	}
	else
		low[u]=min(low[u],low[v]);

之前好像还用这个错误的代码过了一道题来着…
上个图来说明一下上面两个代码的不同之处…
在这里插入图片描述使用错误的代码后会导致3和5号节点分到同一个强连通分量中(都是零)…
理解起来也很简单.手动推一下就很容易看出来为什么.

ACCODE

#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
#include <cstdio>
#define MAX 100010
using namespace std;
struct node{
	int to,nxt;
}edge[MAX],edge2[MAX];
int n,m;
stack<int> st;
int un[MAX];
int head[MAX];
int head2[MAX];
int cnt;
int len;
int low[MAX];
int dfn[MAX];
int vis[MAX];
int ans[MAX];
int k[MAX];
int num;
void tarjan(int u)
{
	dfn[u]=low[u]=++len;
	st.push(u);
	vis[u]=1;
	for(int i=head[u];i!=-1;i=edge[i].nxt)
	{
		int v=edge[i].to;
		if(dfn[v]==0)
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(vis[v])
		low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u])
	{
		num++;
		while(1)
		{
			
			int t=st.top();
			st.pop();
			un[t]=num;
			vis[t]=0;
			if(t==u)
			break;
		}
	}
}

void init()
{
	num=0;
	len=0;
	cnt=0;
	memset(head2,-1,sizeof(head2));
	memset(head,-1,sizeof(head));
	while(!st.empty())
	st.pop();
}

void addedge(int from,int to)
{
	edge[cnt]={to,head[from]};
	head[from]=cnt++;
}

void addedge2(int from,int to)
{
	edge2[cnt]={to,head2[from]};
	head2[from]=cnt++;
}

void sd()
{
	cnt=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=head[i];j!=-1;j=edge[j].nxt)
		{
			int v=edge[j].to;
			if(un[v]==un[i])
				continue;
			addedge2(un[i],un[v]);
		}
	}
}

int dfs(int now)
{
	for(int i=head2[now];i!=-1;i=edge2[i].nxt)
	{
		int v=edge2[i].to;
		if(k[v])
		ans[now]=max(ans[now],ans[v]);
		else
		ans[now]=max(ans[now],dfs(v));
	}
	k[now]=1;
	return ans[now];
}

void getans()
{
	for(int i=1;i<=n;i++)
	ans[un[i]]=max(ans[un[i]],i);
	for(int i=1;i<=n;i++)
	dfs(i);
}
int main()
{
	init();
	scanf("%d%d",&n,&m);
	for(int i=0;i<m;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		addedge(a,b);
	}
	for(int i=1;i<=n;i++)
	if(dfn[i]==0)
		tarjan(i);
	sd();
	getans();
	for(int i=1;i<=n;i++)
		cout<<ans[un[i]]<<" ";
	return 0;
}
/*
5 5
1 2
2 4
4 1
3 1
5 1
*/


发布了30 篇原创文章 · 获赞 9 · 访问量 1308

猜你喜欢

转载自blog.csdn.net/Zhang_sir00/article/details/101292425