(纪中)1932. 奶牛的声音(mooomoo)【DP(完全背包)】

66 篇文章 1 订阅

*(File IO): input:mooomoo.in output:mooomoo.out
时间限制: 1000 ms 空间限制: 128000 KB 具体限制 *


题目描述
农夫约翰最近忘记他有多少奶牛了!于是他决定用一个特别新颖的方法来计算奶牛的数量。他在每块农田上都安装一个麦克风,通过麦克风的音量来计算每个农田上有多少奶牛。
约翰的N个农田是排成一条直线,每个农田上可能拥有不同种类的奶牛,奶牛的种类是 B B B种,第i种奶牛每只奶牛都会发出 V i V_i Vi的音量。然后,由于农场里是经常有风的,风的方向是从左到右的,风使得奶牛的声音也从左到右吹了过去。如果声音在某块农田的音量是 X X X,那么接下来风将把 X − 1 X-1 X1音量的声音带到下一个(右边)那个农田上去。因此每块农田上的音量等于本身这块农田上奶牛发出的声音加上左边相邻的农田音量 X − 1 X-1 X1
给定从左到右每块农田上的音量,请帮助约翰计算他最少有多少数量的奶牛。


输入
第一行两个正整数N和B。
2 2 2行到第 B + 1 B+1 B+1行,第 i + 1 i+1 i+1行的整数表示 V i V_i Vi
B + 2 B+2 B+2行到第 B + i + 1 B+i+1 B+i+1行,表示从左到右每块农田上的监测到的音量。

输出
输出最少可能有多少奶牛,如果不能确定的话,就输出 − 1 -1 1


样例输入
5 2
5
7
0
17
16
20
19

样例输出
4


数据范围限制
1 < = N < = 100 , 1 < = B < = 20 , 1 < = V i < = 100 1<=N<=100,1<=B<=20,1<=Vi<=100 1<=N<=100,1<=B<=20,1<=Vi<=100,每块农田上监测的音量不超过 100000 100000 100000


提示
第一块农田上音量为 0 0 0,所以奶牛数量也为 0 0 0,第二块农田上音量为 17 17 17,由于左边没有声音传过来,所以 17 17 17的音量全部是第二块农田上奶牛产生的,第二块农田上最少有 2 2 2只第 1 1 1种类的奶牛和 1 1 1只第 2 2 2种类的奶牛,接下来第三块农田上的音量是 16 16 16,全部由左边传过来,所以第三块农田没有奶牛,第四块农田上音量是 20 20 20,其中 15 15 15是由第三块农田上传过来的, 5 5 5是自己产生的, 5 5 5的音量最少有1只第一种类的奶牛,所以最少总共有 4 4 4只奶牛。


解题思路
题目大意:
奶牛的声音从左吹到右,逐次 − 1 -1 1累加,有 b b b种奶牛,第i种奶牛每只奶牛都会发出 V i V_i Vi的音量,最少可能有多少奶牛。
这是一个完全背包的方案数问题,动态规划转移方程为
f [ j + v [ i ] ] = m i n ( f [ j ] + 1 , f [ j + v [ i ] ] ) f[j+v[i]]=min(f[j]+1,f[j+v[i]]) f[j+v[i]]=min(f[j]+1,f[j+v[i]]) f [ i ] f[i] f[i]表示音量为 i i i时的方案数。


代码

#include<bits/stdc++.h>
using namespace std;
int n,b,f[100010],a[25],x,s,ans;
int main()
{
	freopen("mooomoo.in","r",stdin);
    freopen("mooomoo.out","w",stdout);
    scanf("%d%d",&n,&b);
    for(int j=0; j<=100005; j++)
        f[j]=2147480000;
	f[0]=0;
    for(int i=1; i<=b; i++)
        scanf("%d",&a[i]);
    for(int i=1; i<=n; i++)
        for(int j=a[i]; j<=100000; j++)
            f[j]=min(f[j-a[i]]+1,f[j]);
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&x);
        if(x==0)continue;
        if(s<=x&&f[x-s]!=2147480000)
            ans+=f[x-s];
        else 
        {
            printf("-1");
            return 0;
        }
        s=x-1;
    }
    printf("%d",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值