拓扑排序(练习题)

拓扑排序

一个图能进行拓扑排序的充要条件是它是有向无环图(DAG)。有入度,出度的概念。BFS,DFS 都能实现。
** BFS **
分为无前驱和无后继的顶点优先。
无前驱
1.先找到入度为零的顶点,入队
2.弹出队首,将其邻居点入度-1,入度=0,入队
3.循环2,直到为空
无解说明不是DAG,未入队的是环路上的点。

P1113 杂务

题目描述

John 有需要完成的 n n n 个杂务的清单,并且这份清单是有一定顺序的,杂务 k   ( k > 1 ) k\ (k>1) k (k>1) 的准备工作只可能在杂务 1 1 1 k − 1 k-1 k1 中。(由于这个,此题不用拓扑也很简单)

写一个程序依次读入每个杂务的工作说明。计算出所有杂务都被完成的最短时间。当然互相没有关系的杂务可以同时工作,并且,你可以假定 John 的农场有足够多的工人来同时完成任意多项任务。

输入格式

第1行:一个整数 n   ( 3 ≤ n ≤ 10 , 000 ) n\ (3 \le n \le 10{,}000) n (3n10,000),必须完成的杂务的数目;

2 2 2 n + 1 n+1 n+1 行,每行有一些用空格隔开的整数,分别表示:

  • 工作序号(保证在输入文件中是从 1 1 1 n n n 有序递增的);
  • 完成工作所需要的时间 l e n   ( 1 ≤ l e n ≤ 100 ) len\ (1 \le len \le 100) len (1len100)
  • 一些必须完成的准备工作,总数不超过 100 100 100 个,由一个数字 0 0 0 结束。有些杂务没有需要准备的工作只描述一个单独的 0 0 0

保证整个输入文件中不会出现多余的空格。

输出格式

一个整数,表示完成所有杂务所需的最短时间。

代码(BFS)

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int ind[500005],f[500005],a[500005];
vector<int> e[500005];
queue<int> q;
signed main()
{
	IOS
	int n,b,c;

	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>b>>a[i];
		while(cin>>c&&c!=0)
		{
			e[c].push_back(i);//e存放出度编号
			ind[i]++;//ind计算入度个数
		}
	}
	for(int i=1;i<=n;i++)//找到入度为零的点存入队列
		if(ind[i]==0)
		{
			q.push(i);
			f[i]=a[i];//完成时间就是单个任务的完成时间
		}
	while(!q.empty())
	{
		int r=q.front();//推出的第一个
		q.pop();
		for(int i=0;i<e[r].size();i++)
		{
			int u=e[r][i];
			ind[u]--;//将r指向的编号入度-1
			if(ind[u]==0) q.push(u);
			f[u]=max(f[u],f[r]+a[u]); //最大的时间是某杂物的完成时间
		}
		
		
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	ans=max(ans,f[i]);
	cout<<ans<<'\n';
	return 0;
	
	 
}

P4017 最大食物链计数

题目描述

给你一个食物网,你要求出这个食物网中最大食物链的数量。
(这里的“最大食物链”,指的是生物学意义上的食物链,即最左端是不会捕食其他生物的生产者,最右端是不会被其他生物捕食的消费者。)
Delia 非常急,所以你只有 1 1 1 秒的时间。
由于这个结果可能过大,你只需要输出总数模上 80112002 80112002 80112002 的结果。

输入格式

第一行,两个正整数 n 、 m n、m nm,表示生物种类 n n n 和吃与被吃的关系数 m m m

接下来 m m m 行,每行两个正整数,表示被吃的生物A和吃A的生物B。

输出格式

一行一个整数,为最大食物链数量模上 80112002 80112002 80112002 的结果。

【补充说明】

数据中不会出现环,满足生物学的要求。(感谢 @AKEE )

代码(BFS)

累加,上一个点的答案累加到下一个点。初始为1,最后每一条路都会累加到出度为零的点,再加一块。所以用向量存出度,要到下一个点,接着算(而dfs,要存入度)

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int ind[500005],sum[500005];//ind放入度,sum累加食物链
const int mod=80112002;
//vector<int> ch[500005];
vector<vector<int>> ch;
queue<int> d;
signed main()
{
	IOS
	ch.resize(500005);
	int n,m,a,b,ans=0;
	cin>>n>>m;
 	for(int i=1;i<=m;i++)
 	{
	 	cin>>a>>b;
		ch[a].push_back(b);//a里存放他的天敌,即出度
		ind[b]++;
	 }
	 for(int i=1;i<=n;i++)
	 {
	 	if(ind[i]==0)//找到食物链底端
	 	{
		 	d.push(i);
		 	sum[i]++;
		 }
	 }
	 while(!d.empty())
	{
		int u=d.front();
		d.pop();
		for(int i=0;i<ch[u].size();i++)
		{
			ind[ch[u][i]]--;
			sum[ch[u][i]]=(sum[ch[u][i]]+sum[u])%mod;//加上它食物的链数
			if(ind[ch[u][i]]==0)
			{
				d.push(ch[u][i]);
			}
			
		}
	} 	
	for(int i=1;i<=n;i++)
	if(ch[i].size()==0)//没有天敌,即顶端加一块
	ans=(ans+sum[i])%mod;
	cout<<ans<<'\n';
	 
}

代码(DFS)

向量存入度结点,需要递归从后往前,最前端写1,在往后累次加

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
vector<vector<int> > ch;
const int mod=80112002;
int out[500005],sum[500005];//out计算出度,sum计算链数
int dfs(int j)
{
	if(ch[j].empty()) //到达食物链底端
	{
	sum[j]=1;
	return 1;
	}
	    for(int i=0;i<ch[j].size();i++)
	   {
		if(sum[ch[j][i]]==0)
		sum[j]=(sum[j]+dfs(ch[j][i]))%mod;
		else
		 sum[j]=(sum[j]+sum[ch[j][i]])%mod;//j点链数等于j点加上他的入度链数
    	}
	   
   	 return sum[j];
}
signed main()
{
   ch.resize(500005);
	int n,m,x,y,ans=0;
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>x>>y;
		out[x]++;
		ch[y].push_back(x);
	}
	for(int i=1;i<=n;i++)
	{
		if(out[i]==0)//找到顶端
		ans=(ans+dfs(i))%mod;
	}
	cout<<ans;
	
}

P1983 [NOIP2013 普及组] 车站分级

题目

在这里插入图片描述

代码

每个火车,从始到终没停的站点,可以看作已停的入度。
入度为0的开始,level为1,往后累加。出度为0中最大的level为答案。这里用的out数组,开始用的vector,MLE,TLE,还有初始化问题。没成功。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
queue<int> q;
//vector<vector <int> > out;不能用
int out[1005][1005];
int n,m,ind[1005],a[1005],level[1005];
void bfstuopu()
{
	for(int i=1;i<=n;i++)
	if(ind[i]==0)
	{
		q.push(i);
		level[i]=1;
	}
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		for(int i=1;i<=n;i++)
		{
			if(out[u][i]==1)
			{
				ind[i]--;
				if(ind[i]==0)
				{
					q.push(i);
					level[i]=level[u]+1;
				}
			}	
		}
	}
}
signed main()
{
	IOS
	int s;
	cin>>n>>m;
	int v[1002];
	for(int i=1;i<=m;i++)
	{
		
		memset(v,0,sizeof(v));
		cin>>s;
		for(int j=1;j<=s;j++)
		{
			cin>>a[j];
			v[a[j]]=1;
		}
	
		for(int j=a[1];j<=a[s];j++)
		if(v[j]==0)
		{
			for(int k=1;k<=s;k++)
			{
				if(out[j][a[k]]==0)
			//	if(find(out[j].begin(),out[j].end(),a[k])==out[j].end()) //加if  不会MLE,但TLE
				{
						out[j][a[k]]=1;
						ind[a[k]]++;
							 
				}	
			}
			
		}	 
	}
	bfstuopu();
	int ans=1;
	for(int i=1;i<=n;i++)
	ans=max(ans,level[i]);
 	cout<<ans;
 
}

二维vector初始化
vector<vector > vec(10,vector(8))
10行8列,全为0

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值