拓扑排序求最长路

洛谷 P1113 杂务
题目传送门
在这里插入图片描述分析:有些杂务必须在另一些杂务完成的情况下才能进行,具有先后关系,可以想到拓扑排序,实际上是拓扑排序求最长路,最后必须要取时间最长的那个,因为要保证所有工作全部做完。
大致思路如下:
1.输入序号 杂物消耗的时间 完成该工作的各项准备工作
用vector存下依赖于i完成后才能进行处理的杂物
就是说准备工作在前,要完成的工作序号在后
cin >> x; //工作序号
cin >> e; //准备工作
vec[e].push_back(x);//建图
一定要注意这个问题,我一开始没理解题意,前后存反了,必须要是准备工作做完才能做这项工作,所以存的时候准备工作在前,要完成的这项工作在后
还有怎么存每项工作的消耗时间,我一开始是直接输入时间tim,然后开了一个数组ti,输入准备工作e之后,我就ti[e]=tim,其实这样时间会不断被覆盖掉,导致出错,其实每项杂物消耗的时间不管这个杂物什么时候做是不变的 ,而且题目说n个杂物清单是有序的,所以时间输入直接是在for循环里输入tim[i]即可
后面就是拓扑排序的板子了
2.记录结点的入度,维护一个队列,度数为0的入队列,这时候别忘了把dp[i]的值置为tim[i],如果不置为tim[i]的话,拿样例来说
1 5 0这组数,dp[1]就是0,但实际上它的dp值为5
3.只要队列不空,拿出队首的杂物now,并用now更新依赖now完成后才能处理的杂物(假设设为nex)的dp[nex]的值。使dp[nex]=max(dp[nex],dp[now]+tim[nex]),再将入度减一,如果入度为0,则加入队列
4.输出最大的dp[i]

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1E5 + 10;
vector<int> vec[maxn];
int indu[maxn];
int dp[maxn];
int tim[maxn];
queue<int> q;
int main() {
	int n;
	cin >> n;
	int x, e;
	for (int i = 1; i <= n; i++) {
		cin >> x; //工作序号
		cin >> tim[i];//每项杂物它消耗的时间不管谁在前谁在后是不变的 
		cin >> e; //准备工作
		while (e) {
			vec[e].push_back(x);//建图
			indu[x]++;
			cin >> e;
		}
	}
	for (int i = 1; i <= n; i++) {
		if (indu[i] == 0) {
			q.push(i);
			dp[i] = tim[i];
		}
	}
	//cout<<dp[1]<<endl;
	while(!q.empty())
	{
	   int now=q.front();
	   q.pop();
	   for(int i=0;i<vec[now].size();i++)
	   {
	   	dp[vec[now][i]]=max(dp[vec[now][i]],dp[now]+tim[vec[now][i]]);
	   	--indu[vec[now][i]];
	   	if(indu[vec[now][i]]==0)
	   	q.push(vec[now][i]);
	   }
	}
	int max=0;
	for(int i=1;i<=n;i++)
	{
		if(dp[i]>max)
		max=dp[i];
	}
	cout<<max<<endl;	
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值