计蒜课--法师康的工人题目(巧妙的解法)
题目描述:
三个法师康的工人每天早上6点到工厂开始到三条产品生产线上组装桔子手机。第一个工人在200时刻开始(从6点开始计时,以秒作为单位)在生产线上开始生产,一直到1000时刻。第二个工人,在700时刻开始,在1100时刻结束。第三个工人从1500时刻工作到2100时刻。期间最长至少有一个工人在生产线上工作的连续时间为900秒(从200时刻到1100时刻),而最长的无人生产的连续时间(从生产开始到生产结束)为400时刻(1100时刻到1500时刻)。
你的任务是用一个程序衡量N个工人在N条产品线上的工作时间列表(1≤N≤5000,以秒为单位)。
·最长的至少有一个工人在工作的时间段
·最长的无人工作的时间段(从有人工作开始计)
输入第1行为一个整数N,第2-N+1行每行包括两个均小于1000000的非负整数数据,表示其中一个工人的生产开始时间与结束时间。输出为一行,用空格分隔开两个我们所求的数。
样例输入
3 200 1000 700 1100 1500 2100
样例输出
900 400
这道题目在我拿到的时候准备用DP来解决,后来花了发现这个题目没有必要用DP(动态规划)来写。之后发现了一个好的方法,比较巧妙所以分享在这里。
分析这个题目的话我们会发现,这个题目不外乎两种情况——当前区间的左边比已知的最大右端点的值小(注意我说的是已知最大值,下面我要放出了代码然后分析下为何要记录已知最大值而不是和上一个区间的右端点比较),而区间右边又比已知最大值大的时候:我们取已经得到的最长工作时间+(区间右端点-已知最大右端点)
第二种情况是区间左端点>已知最大右端点的值。此时比较这个区间与之前得到的最大值哪个更大。而对于最大未工作时间,我们也只有在第二种情况中能得到(因为只有第二个情况里面区间直接有断开)。
下面是代码分析:
#include<iostream> #include<algorithm> using namespace std; struct node{ int left,right; }a[5001]; bool cmp(node x,node y){ if(x.left==y.left)return x.right<y.right; else return x.left<y.left; }
第一部分是定义结构体。在这个程序里我们用结构体更方便一些,然后初始化sort函数的排列方式,按照左端点从小到大排列。
int main(){ int unwork_max=0; int n; cin>>n; for(int i=0;i<n;i++){ cin>>a[i].left>>a[i].right; } sort(a,a+n,cmp); int current_max = a[0].right; int work_max = a[0].right-a[0].left; int work_max_var = a[0].right-a[0].left; for(int h=1;h<n;h++){ if(current_max>=a[h].left) { if(a[h].right>current_max) work_max_var = work_max_var+a[h].right-current_max; } else { work_max_var = a[h].right-a[h].left; unwork_max =max(a[h].left-current_max,unwork_max); } current_max = max(current_max,a[h].right); work_max = max(work_max,work_max_var); }
在主函数里,我定义了current_max变量,为了依次记录当前最大的右端点值。并且这个变量在后面发挥了很大作用。
在循环中,因为只有n个区间,所以也就循环n次,第一个if是我上述第一种情况(像例子给的那样:200 1000 700 1100......),这里700在200和1000里面,所以进入if并且给work_max_var这个变量这个值。
之后在函数后面比较先前的work_max与此时区间的max哪个更大,并把大的覆盖到work_max。并且在后面我们写了一个 current_max = max(current_max,a[h].right); 语句。这个语句是为了持续更新current_max。保证current_max始终是已循环区间的最大右值。不知道大家是否注意到:if(a[h].right>current_max) work_max_var = work_max_var+a[h].right-current_max; 这个函数中我们一直在使用这个current_max 。当current_max特别大的时候,也就意味着这个if永远也进不去了。
而else语句中是上述第二种情况。当(例子:700 1100 1500 2100),此时work_max_var=2100-1500 而nuwork_max中是拿a[h].left-current_max与之前的nuwork_max比较。(这里current_max就很有用了,当记录的current_max很大时,也就意味着之前遍历过的区间内有工作时间很长的 比如:1 到 正无穷。这样的话我就没有工作时间了,那么我的a[h].left-current_max就是一个负值,那理所当然current_max不会变)
写的有一点乱,但是应该是能看懂的,还需要努力呀。加油了!
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Made By Pinging