每日一题——喂牛的麻烦事

 P1113 杂务 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这个题的背景没有用,所以就没截图了。其实一开始我硬是没看懂,我还以为说全部工作时间加起来,可是全加是29,比23大,显然不对。所以就没忍住看题解,没看懂,后来回来认真看了一下题,原来有些工作是可以同时进行的,比如做2 3时也在做4。

解读题意:这个题的大概意思就是先给出工作数目,然后给出序数和完成该工作的时间以及做该工作前需要做的准备工作的序号,以0结尾,什么意思呢?

比如我要做2号工作,那么我需要先完成1号,也就是做完2号花费时间是5 + 2 = 7,想做3号的话,需要先完成2号,即花费时间是10;想做4号只需要完成1号,什么意思?就是我在进行第2项工作时,第4项同时进行,所以做完第4项工作花时是5 + 6 = 11;想做第5项工作的前提是完成第2和第4项工作,完成第2项只花了7,这时候第4项工作还没完成,所以需要等到完成第4项才能开始,即取完成这两项工作所耗时间的最大值,第六第七项工作同理。到这里应该能理解题意了。

那么这个输出是怎么来的?我们通过上面的计算可以得出:

第一项工作花费5

第二项工作花费7

第三项工作花费10

第四项工作花费11 = 5 + 6 = a[1] + t

第五项工作花费12 = 11 + 1 = a[4] + t

第六项工作花费19 = 11 + 8 = a[4] + t

第七项工作花费23 = 19 + 4 = a[6] + t

所以输出的是完成第7项工作花费的时间,然后我就理直气壮地提交上去,拿了10分(T-T)

这里还有一个坑点:完成最后一项工作所花费的时间不见得可以完成所有工作,可能在中间或者哪个位置完成那个工作的时间比完成最后一个工作的时间长,所以我们需要输出完成某个工作所花费的时间的最大值。

//toposort模板
#include <bits/stdc++.h>
#define MOD 1000000007
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
 
int n,maxn;
 
struct node {
	int rudu,ans,t;//入度值,共花费的时间,完成该单项工作花费的时间
	vector<int> edge;//存当前点指向的下一个点(一个箭头的两端,有头的是存进edge的,没头的是结构体) 
} a[10005];
 
queue<int> q;//bfs 
 
int main() {
	cin>>n;
	int nn=n;
	while(nn--) {
		int i,x;
		cin>>i;
		cin>>a[i].t;
		while(cin>>x && x) {//x为前驱 
			a[x].edge.push_back(i);//i为后驱 
			a[i].rudu++;//后驱当然是入度增加 
		}
	}
 
	//toposort的第一步
	for(int i=1; i<=n; i++) {
		if(a[i].rudu==0) {
			q.push(i);//找到入度值为0的点(起点),入队
			a[i].ans=a[i].t;//假设可以直接完成该项工作的时间
		}
	}
 
	//toposort的第二步(BFS实现) 
	while(!q.empty()) {
		int h=q.front();
		q.pop();
		for(int i=0; i<a[h].edge.size(); i++) {
			int j=a[h].edge[i];
			a[j].rudu--;//每掏一次,入度就要-1 
			if(a[j].rudu==0) q.push(j);//入度为0就进队充当下一个起点
			a[j].ans=max(a[j].ans,a[h].ans+a[j].t);//完成该项工作的时间=前驱所花费的时间+当前花费
		}
	}
 
	for(int i=1; i<=n; i++)
	//cout<<a[i].ans<<endl;
	maxn=max(maxn,a[i].ans);
	cout<<maxn; 
	return 0;
}
//dp做法(基于toposort的优化)
#include <bits/stdc++.h>
#define MOD 1000000007
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
int n,maxn;
int s[10005];//存做完第i项工作所需要的时间
int main() {
	int i,t;
	cin>>n;
	while(n--){
		cin>>i;//序号 
		cin>>t;//该项工作需要的时间
		int ans=0;//用于在后面进行前驱的时间比较
		int tt;
		while(cin>>tt && tt) {
			ans=max(ans,s[tt]);//做完条件中的工作所花费的时间 
		}
		s[i]=ans+t;//做完第i项工作需要的时间(前提是完成条件的工作) 
		maxn=max(maxn,s[i]);//比较出完成时间最长的
	}
	cout<<maxn;//完成某个工作所花费的时间的最大值
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_61017400/article/details/124222692
今日推荐