CSU-ACM2017暑假集训比赛1 C - Gourmet and Banquet

本文介绍了一个关于在限定时间内如何最大化品尝不同菜品总时间的问题解决方法。通过贪心算法结合二分查找技术,确保每道菜品被品尝的时间相同并达到最大总品尝时间。

A gourmet came into the banquet hall, where the cooks suggested n dishes for guests. The gourmet knows the schedule: when each of the dishes will be served.

For i-th of the dishes he knows two integer moments in time ai and bi (in seconds from the beginning of the banquet) — when the cooks will bring the i-th dish into the hall and when they will carry it out (ai < bi). For example, if ai = 10 and bi = 11, then the i-th dish is available for eating during one second.

The dishes come in very large quantities, so it is guaranteed that as long as the dish is available for eating (i. e. while it is in the hall) it cannot run out.

The gourmet wants to try each of the n dishes and not to offend any of the cooks. Because of that the gourmet wants to eat each of the dishes for the same amount of time. During eating the gourmet can instantly switch between the dishes. Switching between dishes is allowed for him only at integer moments in time. The gourmet can eat no more than one dish simultaneously. It is allowed to return to a dish after eating any other dishes.

The gourmet wants to eat as long as possible on the banquet without violating any conditions described above. Can you help him and find out the maximum total time he can eat the dishes on the banquet?

Input

The first line of input contains an integer n (1 ≤ n ≤ 100) — the number of dishes on the banquet.

The following n lines contain information about availability of the dishes. The i-th line contains two integers ai and bi (0 ≤ ai < bi ≤ 10000) — the moments in time when the i-th dish becomes available for eating and when the i-th dish is taken away from the hall.

Output

Output should contain the only integer — the maximum total time the gourmet can eat the dishes on the banquet.

The gourmet can instantly switch between the dishes but only at integer moments in time. It is allowed to return to a dish after eating any other dishes. Also in every moment in time he can eat no more than one dish.

Example
Input
3
2 4
1 5
6 9
Output
6
Input
3
1 2
1 2
1 2
Output
0
Note

In the first example the gourmet eats the second dish for one second (from the moment in time 1 to the moment in time 2), then he eats the first dish for two seconds (from 2 to 4), then he returns to the second dish for one second (from 4 to 5). After that he eats the third dish for two seconds (from 6 to 8).

In the second example the gourmet cannot eat each dish for at least one second because there are three dishes but they are available for only one second (from 1 to 2).

这个题一开始题目都没看懂,贼绝望。大意相当于,端菜,上菜,在这中途尝菜,且保证尝的每一个菜的时间相同,并且每一个都尝到。

首先分析下,每个菜端菜上菜时间已知,ai,bi,那么尝菜时间t,必定包含在[ai,bi)中,既然要达到这样的时间t,(首先假设已知这样的t),需要在每一种菜的[ai,bi)中能够找到或连续或不连续的时间段,其和为t,那么显然我们可以使用贪心去求解,首先按照bi的大小,从小到大排列,然后二分可能符合条件的t,只要符合,就选取其中最大的。

证明一下贪心策略的正确性:(即证明贪心策略总是使得再每一种菜的[ai,bi)时间段找到这样的时间段和尽可能为t)

设当前时间为cur,那么再cur这个时间点,应该要用在bu > cur,且bu最小的第u种菜上,假设cur不用在第u种菜上,假设第u种菜已找到这样的时间段和为tu(tu < t,如果tu = t则要忽略),那么再[cur + 1,bu),这个时间段,可以假设为su,su + tu显然可能是小于t的,那么为了让这第u种菜尽可能找到这样的时间段使其和为t,那么必定cur这个时间点应该用再这种菜上。

代码并非是遍历全部时间,而是遍历各种菜的时间段,这显然更好操作,只需要一个visit数组记录当前时间点是否已用掉。

代码:

#include<cstdio>
#include<cctype>
#include<iostream>
#include<stack>
#include<map>
#include<cstring>
#include<string>
#include<sstream>
#include<queue>
#include<set>
#include<algorithm>
#include<queue>
using namespace std;
struct dish{
 int a;
 int b;
}f[10001];
int visit[10001],n;
bool cmp(dish a1,dish b1){
 return a1.b < b1.b;
}
bool check(int time_limit){
 memset(visit,0,sizeof(visit));
 for(int i = 0;i < n;i++){
  int sum = 0;
  for(int j = f[i].a;j < f[i].b;j++){
   if(!visit[j]){
    sum++;
    visit[j] = 1;
    if(sum == time_limit)
     break;
   }
  }
  if(sum < time_limit)
   return false;
 }
 return true;
}
int main()
{
 while(scanf("%d",&n) != EOF){
  int right = 10001;
  for(int i = 0;i < n;i++){
   scanf("%d%d",&f[i].a,&f[i].b);
   right = min(right,f[i].b - f[i].a);
  }
  sort(f,f + n,cmp);
  int left = 1,mid = 1,result = 0;
  while(left <= right){
   mid = (left + right) / 2;
   if(check(mid)){
    result = max(result,mid);
    left = mid + 1;
   }
   else
    right = mid - 1;
  }
  printf("%d\n",result * n);
 }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值