ACM复习(45)10680 飞机

Description
某国成立了一个新的航空公司。该公司准备采购飞机来运营属下的两条航线A与B。他们联系了一些飞机制造商,这些制造商提供了他们飞机的资料。
资料里面记录了每种飞机的载客量,以及他们飞航线A与航线B所需要的燃油量。

通过市场调查,该公司摸清了两条航线的日均客流量。已知该航空公司每日能够采购到一定数目的燃油。目前,该公司在制定采购计划,
对于所有型号的飞机,他们可以采购任意数目。然而,他们正在怀疑,在燃油数目的限制下,他们的采购能否可以满足两条航线的客流量。
请写一个程序解决这个问题,作出回答。

输入格式
测试数据包括多组样例。数据以CASE开头,表示测试样例的数目。
对于每组样例,第1行有两个整数,n与fuel,表示供航空公司采购的飞机种类数目,以及他们每日能够采购到的燃油数目。
(1<=n<=1000, 0<=fuel <= 1000)
第2行有两个整数:p1,p2,表示两条航线每日的客流量。
第3行有n个整数:c1,c2,…,cn,每个数字表示第i个型号的飞机的载客量。
第4行有n个整数:f11,f12,…,f1n,每个数字表示第i个型号的飞机飞航线A的耗油量。
第5行有n个整数:f21,f 22,…,f2n,每个数字表示第i个型号的飞机飞航线B的耗油量。

输出格式
对于每个样例的输出均为一行,包括一个数字:0或者1。
如果采购商给出的飞机列表在燃油的限制条件下,能够满足两条航线的客流,输出1,否则输出0。

输入样例
2
3 16
299 499
100 200 250
2 3 4
3 5 6

3 17
299 499
100 200 250
2 3 4
3 5 6

输出样例
0
1

提示
第一个样例中,有3种飞机可供采购。但是由于每日燃油的限制,无论如何采购,都无法满足两条航线的载客任务。
第二个样例中,有3种飞机可供采购。航线A需要两架飞机运营:第1种飞机1架,第2种飞机1架。航线B需要2架飞机运营:第三种飞机2架。
这个解决方案每日的耗油量是2+3+6+6=17,满足题目要求。


解题思路

计算满足每条航线客运量的最低耗油量 amin,bmin,
totoal = amin + bmin
判断total和可用油量的大小关系即可

最低耗油量计算:
因为每架飞机有载客量和耗油量的概念,所以每条航线的计算都可以当成背包问题
又因为每个型号的飞机可以购买无限架,所以是完全背包问题。

先按一般的完全背包解法求出F[ i ] [ j ],F[ i ] [ j ]表示前 i 个物品在容量为 j 的情况
下所能得到的最大价值(在这里就表示前 i 种飞机在耗油量为 j 的情况下的最大载
客量

然后遍历F[ i ] [ j ]求出满足客运量的最低耗油量

背包九讲

#include<stdio.h>
#include<string.h>
int max(int a, int b){return a > b ? a : b;}
int getMin(int n, int fuel, int total, int value[], int weight[]);
int flag[1001][1001];
int main()
{
    int t, n, fuel, atotal, btotal, amin, bmin, value[1002], aweight[1002], bweight[1002];
    scanf("%d", &t);
    while(t --)
    {
        scanf("%d %d", &n, &fuel);
        scanf("%d %d", &atotal, &btotal);
        for(int i = 0; i < n; i ++)
            scanf("%d", &value[i]);
        for(int i = 0; i < n; i ++)
            scanf("%d", &aweight[i]);
        for(int i = 0; i < n; i ++)
            scanf("%d", &bweight[i]);

        amin = getMin(n, fuel, atotal, value, aweight);
        bmin = getMin(n, fuel, btotal, value, bweight);
        printf("%d\n", amin + bmin > fuel ? 0 : 1);
    }
    return 0;
}
int getMin(int n, int fuel, int total, int value[], int weight[])
{
    int f[1001], min = -1;
    memset(f,0,sizeof(f));
    memset(flag,0,sizeof(flag));
    // 解完全背包
    for(int i = 0; i < n; i ++)
    {
        for(int j = weight[i]; j < fuel; j ++)
            f[j] = max(f[j], f[j - weight[i]] + value[i]);
        // 记录
        for(int k = 0; k < fuel; k ++)
            flag[i][k] = f[k];
    }
    for(int i = 0; i < fuel; i ++)
        for(int j = 0; j < n; j ++)
            if(flag[j][i] >= total)
            {
                min = i;
                goto M;
            }
M:  if(min == -1)
        min = 10000000;
    return min;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值