【BZOJ1179】【Apio2009】Atm 强连通分量缩点+拓扑DP/拓扑最长路 kosaraju+tarjan+dfs转非递归三种代码

5 篇文章 0 订阅
5 篇文章 0 订阅
博客详细介绍了如何使用Kosaraju和Tarjan两种算法解决BZOJ1179和Apio2009的ATM问题,包括递归和非递归版本。文章提供了三种不同的代码实现,讨论了在有限栈空间下如何优化算法。
摘要由CSDN通过智能技术生成

题解:

首先第一个阶段,

可以写kosaraju、也可以写tarjan。

这两种还都分递归和dfs转非递归。

----------------------------------四种方案。

第二个阶段,可以写拓扑DP

也可以写最长路

----------------------------------乘上之前的,,八种方案。


本文写了kosaraju递归版,tarjan递归版,kosaraju非递归版。

……只怪学校oj系统栈太小。。都是逼得啊。


代码1(tarjan):

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 501000
using namespace std;
struct KSD
{
	int u,v,next;
}e[N],E[N];
int head[N],cnt,Head[N];

void add(int u,int v)
{
	cnt++;
	e[cnt].u=u;
	e[cnt].v=v;
	e[cnt].next=head[u];
	head[u]=cnt;
}
void Add(int u,int v)
{
	cnt++;
	E[cnt].v=v;
	E[cnt].next=Head[u];
	Head[u]=cnt;
}

int dfn[N],low[N];
int group,id[N];
bool in[N];

int stk[N],top;
int fee[N],Fee[N];
bool Bar[N],bar[N];
void tarjan(int x)
{
	dfn[x]=low[x]=++cnt;
	stk[++top]=x,in[x]=1;
	for(int i=head[x];i;i=e[i].next)
	{
		if(!dfn[e[i].v])
		{
			tarjan(e[i].v);
			low[x]=min(low[x],low[e[i].v]);
		}
		else if(in[e[i].v])low[x]=min(low[x],dfn[e[i].v]);
	}
	if(low[x]==dfn[x])
	{
		group++;
		do{
			in[stk[top]]=0,id[stk[top]]=group;
			Fee[group]+=fee[stk[top]];
			Bar[group]|=bar[stk[top]];
		}while(stk[top--]!=x);
	}
}
int n,m,s,p;
bool ok[N];
void bfs()
{
	int i,u,v;
	stk[top=1]=s;
	while(top)
	{
		u=stk[top--];
		ok[u]=1;
		for(i=head[u];i;i=e[i].next)
		{
			v=e[i].v;
			if(!ok[v])stk[++top]=v;
		}
	}
}
int dp[N],d[N];
int main()
{
//	freopen("test.in","r",stdin);
	int i,j,k;
	int a,b,c;
	int u,v;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++)scanf("%d%d",&a,&b),add(a,b);
	for(i=1;i<=n;i++)scanf("%d",&fee[i]);
	scanf("%d%d",&s,&p);
	for(i=1;i<=p;i++)scanf("%d",&c),bar[c]=true;

	for(c=cnt,cnt=0,i=1;i<=n;i++)if(!dfn[i])tarjan(i);
	bfs();
	for(cnt=0,i=1;i<=c;i++)
	{
		if((!ok[e[i].u])||(!ok[e[i].v]))continue;
		a=id[e[i].u],b=id[e[i].v];
		if(a==b)continue;
		Add(a,b);
		d[b]++;
	}

	stk[top=1]=id[s];
	int ans=0;
	while(top)
	{
		u=stk[top--];
		if(Bar[u])ans=max(ans,dp[u]+Fee[u]);
		for(i=Head[u];i;i=E[i].next)
		{
			v=E[i].v;
			dp[v]=max(dp[v],dp[u]+Fee[u]);
			d[v]--;
			if(!d[v])stk[++top]=v;
		}
	}
	printf("%d\n",ans);
	return 0;
}


代码2(kosaraju):

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 501000
using namespace std;
struct KSD
{
	int u,v,next;
}e[N],ez[N];
int head[N],lux[N],cnt;
inline void add(int u,int v)
{
	cnt++;
	ez[cnt].v=e[cnt].u=u;
	e[cnt].v=v;
	ez[cnt].next=lux[v];
	e[cnt].next=head[u];
	head[u]=lux[v]=cnt;
}
inline void add2(int u,int v)
{
	cnt++;
	ez[cnt].v=v;
	ez[cnt].next=lux[u];
	lux[u]=cnt;
}

bool vis[N];
int dfn[N],top;
int id[N],group;

int n,m,s,p;
int fee[N];
bool bar[N];

int Fee[N];
bool Bar[N];

void dfs1(int x)
{
	vis[x]=1;
	for(int i=head[x];i;i=e[i].next)if(!vis[e[i].v])dfs1(e[i].v);
	dfn[++top]=x;
}
void dfs2(int x)
{
	id[x]=group;
	Bar[group]|=bar[x];
	Fee[group]+=fee[x];
	for(int i=lux[x];i;i=ez[i].next)if(!id[ez[i].v])dfs2(ez[i].v);
}
int d[N],dp[N];
bool ok[N];
void bfs()
{
	int i,u,v;
	dfn[top=1]=s;
	while(top)
	{
		u=dfn[top--];
		ok[u]=1;
		for(i=head[u];i;i=e[i].next)
		{
			v=e[i].v;
			if(!ok[v])dfn[++top]=v;
		}
	}
}
int main()
{
//	freopen("test.in","r",stdin);
	int i,j,k;
	int a,b,c;
	scanf("%d%d",&n,&m);
	while(m--)scanf("%d%d",&a,&b),add(a,b);
	for(i=1;i<=n;i++)scanf("%d",&fee[i]);
	scanf("%d%d",&s,&p);
	while(p--)scanf("%d",&c),bar[c]=true;

	bfs();
	for(i=1;i<=n;i++)if(!vis[i])dfs1(i);
	for(i=top;i;i--)if(!id[dfn[i]])group++,dfs2(dfn[i]);
	memset(lux,0,sizeof(lux));
	c=cnt,cnt=0;

	for(i=1;i<=c;i++)
	{
		if(!ok[e[i].u])continue;
		a=id[e[i].u],b=id[e[i].v];
		if(a==b)continue;
		add2(a,b);
		d[b]++;
	}
	dfn[top=1]=id[s];
	int ans=0;
	while(top)
	{
		a=dfn[top--];
		if(Bar[a])ans=max(ans,dp[a]+Fee[a]);
		for(i=lux[a];i;i=ez[i].next)
		{
			c=ez[i].v;
			dp[c]=max(dp[c],dp[a]+Fee[a]),d[c]--;
			if(!d[c])dfn[++top]=c;
		}
	}
	printf("%d\n",ans);
	return 0;
}


代码3(kosaraju+主要部分转非递归):

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 501000
using namespace std;
struct KSD
{
	int u,v,next;
}e[N],ez[N];
int head[N],lux[N],cnt;
inline void add(int u,int v)
{
	cnt++;
	ez[cnt].v=e[cnt].u=u;
	e[cnt].v=v;
	ez[cnt].next=lux[v];
	e[cnt].next=head[u];
	head[u]=lux[v]=cnt;
}
inline void add2(int u,int v)
{
	cnt++;
	ez[cnt].v=v;
	ez[cnt].next=lux[u];
	lux[u]=cnt;
}
 
bool vis[N];
int dfn[N],top;
int id[N],group;
 
int n,m,s,p;
int fee[N];
bool bar[N];
 
int Fee[N];
bool Bar[N];

int stk[N];
int which[N];
inline void dfs1(int x)
{
	int i,u,v;
	vis[x]=1;
	which[x]=head[x];
	stk[top=1]=x;
	while(top)
	{
		u=stk[top];
		i=which[u];
		if(!i)
		{
			top--;
			dfn[++cnt]=u;
			continue;
		}
		if(!vis[v=e[i].v])
		{
			vis[v]=1;
			which[v]=head[v];
			stk[++top]=v;
		}
		which[u]=e[i].next;
	}
}/*   ***************************************这个注释部分的dfs转非递归写挂了
inline void dfs2(int x)
{
	int i,u,v;
	stk[top=1]=x;
	group++;
	while(top)
	{
		u=stk[top--];
		id[u]=group;
		Bar[group]|=bar[u];
		Fee[group]+=fee[u];
		for(i=lux[u];i;i=ez[i].next)
			if(!id[v=ez[i].v])
				stk[++top]=v;
	}
}*/
void dfs2(int x)
{
	id[x]=group;
	Bar[group]|=bar[x];
	Fee[group]+=fee[x];
	for(int i=lux[x];i;i=ez[i].next)if(!id[ez[i].v])dfs2(ez[i].v);
}
int d[N],dp[N];
bool ok[N];
void bfs()
{
	int i,u,v;
	dfn[top=1]=s;
	while(top)
	{
		u=dfn[top--];
		ok[u]=1;
		for(i=head[u];i;i=e[i].next)
		{
			v=e[i].v;
			if(!ok[v])dfn[++top]=v;
		}
	}
}
int main()
{
//	freopen("test.in","r",stdin);
	int i,j,k;
	int a,b,c;
	scanf("%d%d",&n,&m);
	while(m--)scanf("%d%d",&a,&b),add(a,b);
	for(i=1;i<=n;i++)scanf("%d",&fee[i]);
	scanf("%d%d",&s,&p);
	while(p--)scanf("%d",&c),bar[c]=true;
	c=cnt,cnt=0;

	bfs();
	for(cnt=0,i=1;i<=n;i++)if(!vis[i])dfs1(i);
	for(cnt=0,i=n;i;i--)if(!id[dfn[i]])group++,dfs2(dfn[i]);
	memset(lux,0,sizeof(lux));
 
	for(cnt=0,i=1;i<=c;i++)
	{
		if(!ok[e[i].u])continue;
		a=id[e[i].u],b=id[e[i].v];
		if(a==b)continue;
		add2(a,b);
		d[b]++;
	}
	dfn[top=1]=id[s];
	int ans=0;
	while(top)
	{
		a=dfn[top--];
		if(Bar[a])ans=max(ans,dp[a]+Fee[a]);
		for(i=lux[a];i;i=ez[i].next)
		{
			c=ez[i].v;
			dp[c]=max(dp[c],dp[a]+Fee[a]),d[c]--;
			if(!d[c])dfn[++top]=c;
		}
	}
	printf("%d\n",ans);
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值