第二层第一题:挤牛奶

      尼玛。。。有暴 力两个字不让发。。。暴 力算法就怎么不行了?瞧不起人家?= =!

Milking Cows

Three farmers rise at 5 am each morning and head for the barn to milkthree cows. The first farmer begins milking his cow at time 300 (measured inseconds after 5 am) and ends at time 1000. The second farmer begins at time 700and ends at time 1200. The third farmer begins at time 1500 and ends at time2100. The longest continuous time during which at least one farmer was milkinga cow was 900 seconds (from 300 to 1200). The longest time no milking was done,between the beginning and the ending of all milking, was 300 seconds (1500minus 1200).

Your job is to write a program that will examine a list of beginning andending times for N (1 <= N <= 5000) farmers milking N cows and compute(in seconds):

  • The longest time interval at least one cow was milked.
  • The longest time interval (after milking starts) during which no cows were being milked.

PROGRAM NAME: milk2

INPUT FORMAT

Line 1:

The single integer

Lines 2..N+1:

Two non-negative integers less than 1,000,000, respectively the starting and ending time in seconds after 0500

SAMPLE INPUT (file milk2.in)

3

300 1000

700 1200

1500 2100

 

OUTPUT FORMAT

A single line with two integers that represent thelongest continuous time of milking and the longest idle time.

SAMPLE OUTPUT (file milk2.out)

900 300

 

 

 

       题目大意是有N个农民,每个农民都会在某个时间点到某个时间点来挤牛奶,问从第一个农民来挤牛奶开始,到最后一个农民挤完牛奶为止,有人在挤牛奶的时间段最长有多长和没有人在挤牛奶的时间段最长有多长。。。

       楼主一看这题,卧槽不是线段树的模板题?果断半个小时种完一棵线段树交了,然后。。。进程被杀死,怀疑有内存超限?楼主上度娘查了一下,发现USACO的内存限制16M      (╯‵□′)╯︵┻━┻3 尼玛真的大丈夫?

       悲催的楼主只好再去想别的算法。。。于是就考虑到了纯暴 力解法,就是将时间轴变为一个bool数组,然后每次输入时间段时将一整段时间的下标变为true,这样子做的时间最坏会有o(n*t)(农民个数n,时间轴长度t),在这题中,n最大为5000,t最大达到1000000,明显超时。但,从这里楼主找到了优化动机!

       试想一下,我们为何会将一个时间点重复赋值?答案是由于给出的时间段的重叠,重叠的次数越多,重复赋值所花费的时间越大。那么,把重叠消除掉不就万事大吉了?于是开一个队列,将有机会与其他时间段合并的时间段放进队列,再按顺序出队。尝试与其它时间段合并,若合并成功,则标记掉被合并的时间段,这样子若被合并的时间段已在队列中,在它再次出队时将不会再次尝试与别的时间段合并,产生的新时间段再放进队列,再去尝试与其它时间段合并,直到队列为空,此时尚未被标记掉的时间段两两之间必不重合,这时我们就可以放心大胆地对代表时间轴的数组操作了。

       接下来评估时间,每个时间段最多入n次队(与其它各个时间段各合并一次,若是与新产生出来的时间段合并,则视为与参与产生该时间段的所有时间段各合并一次了),合并完后对时间轴的操作次数不超过时间轴的长度,则时间加起来总共有o(n2+t),差不多水过。

       附上代码:

/*
ID:su1q2d2
LANG:C++
TASK:milk2
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<cmath>
#define maxn 5010
#define inf 0x7fffffff
#define maxtime 1000010
using namespace std;
struct interval
{
	int op,ed;
}farmers[maxn];
bool deserted[maxn];
bool haveman[maxtime];
int main()
{
	freopen("milk2.in","r",stdin);
	freopen("milk2.out","w",stdout);
	int n;
	int i;
	int s;
	int bg,cl;
	int ol,no;
	int lol,lno;
	bool f;
	queue<int> que;
	scanf("%d",&n);
	bg=inf;
	cl=0;
	memset(haveman,0,sizeof(haveman));
	for(i=1;i<=n;i++){
		que.push(i);
		deserted[i]=false;
		scanf("%d%d",&farmers[i].op,&farmers[i].ed);
		cl=max(cl,farmers[i].ed);
		bg=min(bg,farmers[i].op);
	}
	bg++;
	while(!que.empty()){
		s=que.front();
		que.pop();
		if(!deserted[s]){
			f=true;
			for(i=1;i<=n;i++){
				if(i!=s && !deserted[i]){
					if(farmers[s].ed>=farmers[i].op && farmers[s].op<farmers[i].ed){
						farmers[s].ed=max(farmers[s].ed,farmers[i].ed);
						farmers[s].op=min(farmers[s].op,farmers[i].op);
						deserted[i]=true;
						que.push(s);
						f=false;
						break;
					}
					if(farmers[i].ed>=farmers[s].op && farmers[i].op<farmers[s].ed){
						farmers[i].ed=max(farmers[i].ed,farmers[s].ed);
						farmers[i].op=min(farmers[i].op,farmers[s].op);
						deserted[s]=true;
						que.push(i);
						f=false;
						break;
					}
				}
			}
			if(f){
				for(i=farmers[s].op+1;i<=farmers[s].ed;i++) haveman[i]=true;
			}
		}
	}
	ol=0;
	no=0;
	lol=0;
	lno=0;
	for(i=bg;i<=cl;i++){
		if(haveman[i]){
			ol++;
			lno=max(lno,no);
			no=0;
		}
		else{
			no++;
			lol=max(lol,ol);
			ol=0;
		}
	}
	lno=max(lno,no);
	lol=max(lol,ol);
	printf("%d %d\n",lol,lno);
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值