PTA装修

文章讲述了作者胡伟平面临新房装修问题,如何通过使用拓扑排序算法合理安排多个装修师傅的工作,确保所有环节按顺序完成,同时考虑每个环节的延迟,以尽早完成整个装修过程。

作者 胡伟平

单位 广西科技大学

胡老师买了新房,正在搞装修,装修公司太坑了,于是胡老师就自己找装修师傅来干活,但是装修的很多环节是环环相扣的,比如,要先刷墙才能铺木地板,有些环节呢,又是互相不干扰的,比如厨房的装修和窗帘的安装。但是每个装修师傅的时间又受他接的单所限制。所以必须仔细安排才能把房子装修好。胡老师收到了若干种不同装修师傅的安排,他想尽快装修好了入住,你能帮他吗?

输入格式:

第一行输入正整数T(T< 20),表示有T个方案,对于每一个方案,第一行输入两个正整数N(< 100)和M,其中N是装修时间点的个数,从0开始编号,M是装修环节的个数。随后M行,每行输入三个非负整数表示一个装修环节,Start End Delay,Start表示开始时间点编号,End表示结束时间点编号,Delay表示装修需要时间。

输出格式:

对每一个方案,如果方案可行,则在一行里输入最早结束的时间,如果不可行,则输出Impossible!

输入样例:

在这里给出一组输入。例如:

2
7 10
0 1 3
0 2 2
0 3 6
1 3 2
2 3 1
1 4 4
3 4 1
2 5 3
4 6 3
5 6 4
3 3
0 1 1
1 2 2
2 0 3

输出样例:

在这里给出相应的输出。例如:

10
Impossible!

 经典的拓扑排序,但这里有一个注意点,一个房间最快完成时间不取决于最快在这个房间的步骤,而是最晚完成的步骤。

例如:在没有前置任务的情况下完成房间地板安装需要10分钟,窗户安装8分钟,刷墙5分钟,那么这个房间最快完成时间就是10分钟。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl "\n"

ll n,m,sum,cnt;
ll v[1007],js[1007];//入度,房间最早结束时间 
map<ll,map<ll,ll> >mp;
queue<ll>q;
vector<ll>lian[1007];

void tp(){
	while(!q.empty()){
		ll x=q.front();//当前装修到哪个房间
		//当前房间的最晚时间,前一个房间的最晚时间+此步骤装修房间所需时间 
		for(auto it : mp[x])js[x]=max(js[x],js[it.first]+it.second);
		cnt=max(cnt,js[x]);1
		q.pop();//以下为拓扑模板 
		for(ll i = 0 ; i < lian[x].size() ; i ++){
			v[lian[x][i]]--;
			if(v[lian[x][i]] == 0){
				sum++;
				q.push(lian[x][i]);
			}
		}
	}
}

void solve(){
	cin >> n >> m;
	memset(v,0,sizeof v);//初始化 
	for(ll i = 0 ; i < n ; i ++)lian[i].clear();
	while(!q.empty())q.pop();mp.clear();
	while(m --){
		ll x,y,z;
		cin >> x >> y >> z;
		mp[y][x]=z;//注意,是先完成x房间再完成y房间 
		v[y]++;//拓扑的入度++
		lian[x].push_back(y);//建立拓扑的链表
	}
	sum=0,cnt=0;
	for(ll i = 0 ; i < n ; i ++)
		if(!v[i])q.push(i),sum++;
	memset(js,0,sizeof js);
	tp();
	if(sum < n)cout << "Impossible!" << endl;
	else cout << cnt << endl;
	return;
}

int main(){
	ll t=1;cin >> t;
	while(t--)solve();
	return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值