现在的位置: 首页 > 综合 > 正文

模拟赛 Graph(时间限制:1s;内存限制:128MB)

2018年04月24日 ⁄ 综合 ⁄ 共 2691字 ⁄ 字号 评论关闭

题目描述

给出 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)。

样例输入

4 3
1 2
2 4
4 3

样例输出

4 4 3 4

数据范围

对于 60% 的数据,1 ≤ N,K ≤ 10^3
对于 100% 的数据,1 ≤ N,M ≤ 10^5。

题解

这道题正着做反着做都可以。

正着做要强连通分量缩点,可是T了一个大数据。可能是我写得有问题。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#define MAXN 100002
using namespace std;
int n,m,zz,head[MAXN],cnt,hd[MAXN];
struct bian{int to,nx;} e[MAXN],E[MAXN];
int pre[MAXN],low[MAXN],sccnum[MAXN],ct,scc;
int stack[MAXN],v[MAXN],in[MAXN],top,done[MAXN];
//------------------------------------------------------------------
void insert(int x,int y)
{zz++; e[zz].to=y; e[zz].nx=head[x]; head[x]=zz;}
void init()
{
	scanf("%d%d",&n,&m);
	int i,x,y;
	for(i=1;i<=m;i++)
	   {scanf("%d%d",&x,&y);
	    insert(x,y);
	   }
}
//----------------------------------------------------------------------------
void dfs(int x)
{
	pre[x]=low[x]=++ct;
	stack[++top]=x;
	int i,p;
	for(i=head[x];i;i=e[i].nx)
	   {p=e[i].to;
		if(!pre[p]) {dfs(p); low[x]=min(low[x],low[p]);}
		else if(!sccnum[p]) low[x]=min(low[x],pre[p]);
	   }
	p=-1;
	if(low[x]==pre[x])
	   {scc++;
		while(p!=x)
	       {p=stack[top]; top--;
		    sccnum[p]=scc; v[scc]=max(v[scc],p);
		   }
	   }
}
void tarjan()
{
	int i;
	for(i=1;i<=n;i++)
	   {if(!pre[i]) dfs(i);}
	//for(i=1;i<=n;i++) printf("%d ",sccnum[i]);
	//printf("\n");
	//system("pause");
}
void rebuild()
{
	int x,i,p;
	for(x=1;x<=n;x++)
	for(i=head[x];i;i=e[i].nx)
	   {p=e[i].to;
		if(sccnum[x]!=sccnum[p])
		   {cnt++; E[cnt].to=sccnum[p]; E[cnt].nx=hd[sccnum[x]]; hd[sccnum[x]]=cnt;
		    in[sccnum[p]]++;
		   }
	   }
	//for(i=1;i<=scc;i++) printf("%d ",in[i]);
	//printf("\n");
	//system("pause");
}
//------------------------------------------------------------------------------
void find(int x)
{
	if(done[x]) return;
	int i,p;
	done[x]=1;
	for(i=hd[x];i;i=E[i].nx)
	   {p=E[i].to;
	    find(p);
	    v[x]=max(v[x],v[p]);
	   }
}
void work()
{
	int i;
	for(i=1;i<=scc;i++)
	   {if(in[i]==0) find(i);}
	for(i=1;i<=n;i++)
	   {printf("%d",v[sccnum[i]]);
	    if(i<n) printf(" ");
	    else printf("\n");
	   }
}
int main()
{
	freopen("graph.in","r",stdin);
	freopen("graph.out","w",stdout);
	init(); tarjan();
	rebuild(); work();
	return 0;
}

反着做只要保证每个点走一次即可。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#define MAXN 100002
using namespace std;
int n,m,zz,head[MAXN];
struct bian{int to,nx;} e[MAXN];
int ans[MAXN],done[MAXN];
void insert(int x,int y)
{zz++; e[zz].to=y; e[zz].nx=head[x]; head[x]=zz;}
void init()
{
	scanf("%d%d",&n,&m);
	int i,x,y;
	for(i=1;i<=m;i++)
	   {scanf("%d%d",&x,&y);
	    insert(y,x);
	   }
}
void dfs(int x)
{
	if(done[x]) return;
	int i,p;
	done[x]=1;
	for(i=head[x];i;i=e[i].nx)
	   {p=e[i].to;
		if (!done[p])
	       {ans[p]=max(ans[p],ans[x]);
		    dfs(p);
		   }
	   }
}
void work()
{
	int i;
	for(i=n;i>=1;i--) ans[i]=i;
	for(i=n;i>=1;i--) dfs(i);
	for(i=1;i<=n;i++) printf("%d ",ans[i]);
}
int main()
{
	freopen("graph.in","r",stdin);
	freopen("graph.out","w",stdout);
	init(); work();
	return 0;
}

抱歉!评论已关闭.