pku 3038 Flying Right 贪心 解题报告

本文介绍了一个关于飞机航线调度的问题,采用贪心算法解决如何在有限的飞机座位数下,尽可能多地运送奶牛从一个机场到另一个机场。文章详细分析了算法的思路及实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

pku 3038 Flying Right 解题报告

此题可是让我贡献n多个wa,不写个解题报告,可真对不住自己了;而且我在百度与google还没有找到此题的解题报告(目前来说,我搜索不到)。

题意:    

约翰的奶牛们开通了一条飞机航线,专门为奶牛服务。每天早上,她们沿着密歇根湖的西岸,从线路的最北端出发飞到最南端,全程经过N个机场(包括头尾两个)。到了下午,她们又会沿着同样的路线飞回最北端。每天都会有数目不同的K群奶牛要求乘坐飞机,一群牛会在某一个机场等待,并希望飞到另外一个特定的机场。

       飞机上只能同时容纳C头奶牛乘客,航班的负责牛希望知道在这一天中她们最多可以满足多少头奶牛的要求。飞机可以只将一群牛中的一部分带到目的地。

       约定:1N10,0001K50,0001C100

sample为例:

输入k=4n=8c=3

随后输入k行,每行输入3个数据,分别表示为为sem或者esm(其中s<em<c),意思是从se)站飞到es)站有m头牛要从se)站飞到es)站。可是飞机最多可以容纳c头牛。那么请问可以飞机在一天内最多可以送多少偷牛从地点到终点。

Sample的解法是这样的:1站到3站送2头牛,在到达2站的过程中载多一头牛,目的地是8站;到了3站,有2头牛到站,飞机就还可以容纳2头牛;飞到4站,载多1头牛,送到7站;同理到了8站就有1头牛下飞机。同理可知8站到3站可以送2头牛到达目的地。那么计算可得,一天内有8头牛到站。

算法:

此题刚开始我觉得貌似dp,可是画出图的时候就出问题了,线与线之间有重叠。我根本就想不出其最优子结构。于是放弃用dp了。与网友讨论可知,此题好像加入贪心的思想。想想看:其实我们只是讨论送去的情况就ok,返回时做多一次就ok了,但要相反来做。我们就做一次我们可以对每个座位进行贪心,我们根据那群牛最快到达终点,那么这个座位就选择这头牛,此头牛到达目的地后了,再选择一头牛。那么对c个座位扫描一次,就可以将结果求出来了。

关键代码:

void solve(Data process[], int p)

{ 

nt i, j, k;

qsort(process, p, sizeof(process[0]), cmp);

for (i = 1; i <= c; i++)

{

for (j = 0, k = 0; j < p; j++)

{

if (process[j].start > k && process[j].numbercows > 0)

{ 

k = process[j].end;     //k表示下一头牛的起点站必须大于》k

process[j].numbercows--;//此群牛的数量-1

result++;               //结果+1

}

}

}

}

可这是错误的。Wa n多个。

想了很久,不知道错在哪里。在网上搜索一下,发现这是贾由写的一篇论文中有一道题就是讲述此题。马上打印重新分析。再经过与网友的讨论,发现贪心是需要全部座位一起贪心的!而不是每个座位去贪。想想看每个座位来贪心的话,那么有些数据就不可能通过了。不符合实际。例如 c= 3 1 3 12 4 1 3 5 4。每个座位贪心的话,只能为4,但实际上却可以为5的。那么此种贪心就被抛弃了。于是,我们想到另一个贪心模式:每个站每个站来贪心。在一个站中,有2头牛抢一个位置,那么就看谁的目的地是较近的,也就是说我们选择前往目的地最近的那头牛。可如果在飞机上的牛的目的地比还没有上飞机的牛的目的地还远,那么它就应该驱逐下去,另一头牛上飞机。正如贾由所说,不牛道,但这个算法无疑是最好的。

AC代码:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#define M 50005

 

struct Data

{

       int start, end, numbercows;

};

Data sent[M], back[M];

int k, n, c, s, b, result;

 

int cmp(const void *a , const void *b)

{

       return (*(Data *)a).end - (*(Data *)b).end;

}

 

int comp(const void *a , const void *b)

{

       return (*(Data *)a).start - (*(Data *)b).start;

}

 

void init()

{

       int i, a, bb, cc;

 

       for (i = 0, s = 0, b = 0; i < k; i++)

       {

              scanf("%d%d%d", &a, &bb, &cc);

              if (a <= bb)

              {

                     sent[s].start = a;

                     sent[s].end = bb;

                     sent[s++].numbercows = cc;

              }

              else

              {

                     back[b].start = bb;

                     back[b].end = a;

                     back[b++].numbercows = cc;

              }

       }

}

 

Data temp[M], res[M];

void solve(Data process[], int p)

{

       int i, j, k, sum, now = 0, process_now = 0;

 

       memset(res, 0, sizeof(res));

       memset(temp, 0, sizeof(temp));

       qsort(process, p, sizeof(process[0]), comp);

       for (i = 1; i <= n; i++)

       {

              k = 0;

              for (j = 0; j < now; j++)

              {

                     //res保存可能是结果的数据,每一次扫描都应该要从头更新

                     if (res[j].end == i)

                     {

                            result += res[j].numbercows;

                     }

                     else

                     {

                            //不符合,那么存放在临时的temp,以便在这一站与其他牛重新排序。

                            temp[k++] = res[j];

                     }

              }

              for (j = process_now; j < p; j++)

              {

                     if (process[j].start == i)

                     {

                            //符合要求的

                            temp[k++] = process[j];

                            process_now++;

                     }

              }

              //选择离目的地较近的牛群,并存储到res计算。

              qsort(temp, k, sizeof(temp[0]), cmp);

              sum = 0, j = 0, now = 0;

              while (j < k && sum < c)

              {

                     res[now++] = temp[j++];

                     sum += temp[j - 1].numbercows;

              }

              if (sum > c)

              {

                     res[now - 1].numbercows -= sum - c;

              }

       }

}

 

int main()

{

       while (scanf("%d%d%d", &k, &n, &c) > 0)

       {

              memset(sent, 0, sizeof(sent));

              memset(back, 0, sizeof(back));

              init();

              result = 0;

              solve(sent, s);

              solve(back, b);

              printf("%d/n", result);

       }

       return 0;

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值