Codeforces 158E Phone Talks:dp

题目链接:http://codeforces.com/problemset/problem/158/E

题意:

  你有n个电话要接,每个电话打进来的时刻为第t[i]分钟,时长为d[i]分钟。

  每一个电话打进来时,你有两种选择:

    将电话挂掉,或接听(如果当时正在打其他电话,则这个电话加入等待队列,等上一个电话打完后立马接听)

  你最多能挂掉k个电话。

  时间从第1分钟开始算,一直到86400分钟结束,问你能够获得的最长连续间隔为多长时间。

 

题解:

  表示状态:

    dp[i][j] = clocks

    表示打了前i个电话,挂掉了其中j个电话,打完这些电话的最早时刻。

 

  找出答案:

    有一个贪心结论,就是这k次挂电话的机会必须用完。

    特别地,t[n+1] = 86401。

    ans = min t[i+1]-dp[i][k]-1

 

  如何转移:

    dp[i][j] = min( max(dp[i-1][j]+d[i],t[i]+d[i]-1), dp[i-1][j-1] )

    对于第i个电话,要么接,要么不接。

    如果接,则第i个电话开始的时刻为max(dp[i-1][j]+1, t[i]),所以结束时刻为max(dp[i-1][j]+d[i],t[i]+d[i]-1)。

    如果不接,则最后时刻还是dp[i-1][j-1]。

 

  边界条件:

    dp[0][0] = 0

    others = INF

    另外,当n == 0时要特判,直接输出86400即可。

 

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define MAX_N 4005
 5 #define MAX_K 4005
 6 
 7 using namespace std;
 8 
 9 int n,k;
10 int t[MAX_N];
11 int d[MAX_N];
12 int dp[MAX_N][MAX_K];
13 
14 void read()
15 {
16     cin>>n>>k;
17     for(int i=1;i<=n;i++)
18     {
19         cin>>t[i]>>d[i];
20     }
21     t[n+1]=86401;
22 }
23 
24 void work()
25 {
26     if(n==0)
27     {
28         cout<<"86400"<<endl;
29         return;
30     }
31     memset(dp,0x3f,sizeof(dp));
32     dp[0][0]=0;
33     for(int i=1;i<=n;i++)
34     {
35         for(int j=0;j<=min(i,k);j++)
36         {
37             dp[i][j]=max(dp[i-1][j]+d[i],t[i]+d[i]-1);
38             if(j>0) dp[i][j]=min(dp[i][j],dp[i-1][j-1]);
39         }
40     }
41     int ans=0;
42     for(int i=1;i<=n;i++)
43     {
44         ans=max(ans,t[i+1]-dp[i][k]-1);
45     }
46     cout<<ans<<endl;
47 }
48 
49 int main()
50 {
51     read();
52     work();
53 }

 

posted @ 2018-01-11 17:20  Leohh  阅读(268)  评论(0编辑  收藏  举报