NOIP2011 观光公交 解题报告(贪心(贪心一次更新一次))

在线评测:

http://codevs.cn/problem/1139/


整体思路:

我们先记录一下每个站点的最晚到达的乘客的到达时间,然后我们也可以记录每个站点到下一个站点的路程上车上的人数,并将其维护成一个前缀和,同时我们初始化出到达每个景点的时间,

for (int i = 2;i <= n;i++)
	{
		dd[i] = max(zw[i - 1],dd[i - 1]) + t[i - 1];
	}

并求出乘客的总的时间,

for (int i = 1;i <= m;i++)
		ans += dd[zd[i]] - cf[i];

然后我们可以贪心至多k次,贪减少时间最多的,(选择一个点释放氮气,使其使乘客减少的时间最多),并更新相关数组,到达每个点的时间,两点间的距离,贪心到氮气用光,或者每条路径都无法缩短为止。

失误之处:

维护两点间距离时,傻傻的一直修改的到达时间,,(这样还过了样例和一个点,数据水,,)

体会心得:

明确每个数组的定义,不要搞错,也不要随便糊弄过去,


AC代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using  namespace  std;
int  n,m,k,t[11000],cf[11000],qd[11000],zd[11000];
int  zw[11000],rs[11000],dd[11000],ans,g[11000];
void  sread()
{
     scanf ( "%d%d%d" ,&n,&m,&k);
     for  ( int  i = 1; i < n;i++)
         scanf ( "%d" ,&t[i]);
     for  ( int  i = 1;i <= m;i++)
     {
         scanf ( "%d%d%d" ,&cf[i],&qd[i],&zd[i]);
     }
}
void  init()
{
     for  ( int  i = 1;i <= m;i++)
     {
         zw[qd[i]] =  max(zw[qd[i]],cf[i]);
         rs[zd[i]]++;
     }
     for  ( int  i = 1;i <= n;i++)
         rs[i] = rs[i - 1] + rs[i];
     for  ( int  i = 2;i <= n;i++)
     {
         dd[i] = max(zw[i - 1],dd[i - 1]) + t[i - 1];
     }
     for  ( int  i = 1;i <= m;i++)
         ans += dd[zd[i]] - cf[i];
 
}
void  swork()
{
     while (k)
     {
         g[n] = n;
         g[n - 1] = n;
         for  ( int  i = n - 2;i >= 1;i--)
         {
             if  (dd[i + 1] <= zw[i + 1]) g[i] = i + 1; else  g[i] = g[i + 1];
         }
         k--;
         int  maxn = 0,maxw = 0;
         for  ( int  i = 1;i < n;i++)
         {
             if  (rs[g[i]] - rs[i] > maxn && t[i] > 0)
             {
                 maxn = rs[g[i]] - rs[i];
                 maxw = i;
            
         }
//      printf(" maxn = %d\n",maxn);
         if  (!maxn)  break ;
         t[maxw]--;
         ans -= maxn;
//      printf("jian %d\n",maxn);
         for  ( int  i = maxw + 1;i <= n;i++)
             dd[i] = max(dd[i - 1],zw[i - 1]) + t[i - 1];
     }
     printf ( "%d\n" ,ans);
}
int  main()
{
     sread(); 
     init();
     swork();
     return  0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值