奶牛专题(必练)

有一只奶牛叫贝西,它生活在农场里,请用c++解决问题。

(注:本专辑题目均摘自国外竞赛题目,主要考察代码能力、逻辑能力和种种数学能力,十分有挑战性)

问题 A: 被挡住的广告牌(本题默认有平面直角坐标系基础的人)

题目描述

在漫长的挤奶过程中,奶牛贝西喜欢盯着谷仓的窗户,看街对面两个巨大的长方形广告牌,上面写着“农场主亚历克斯的令人惊叹的美味苜蓿”和“农场主格雷格的伟大谷物”。在贝西看来,广告牌上的这两种牛饲料产品比她农场里的草好吃多了。

一天,当贝西凝视窗外时,她惊恐地看到街对面停着一辆巨大的长方形卡车。卡车的一侧有一个“农夫史密斯的超级牛排”的广告,贝茜不太明白,但她最担心的是卡车可能会挡住她最喜欢的两个广告牌的视线。

考虑到两个广告牌的位置和卡车的位置,请计算两个广告牌仍然可见的总面积。有可能卡车掩盖了两个广告牌中的任何一个,或者两个,或者只有一个。

输入

第一行输入包含四个用空格分隔的整数:x1 y1 x2 y2,其中(x1,y1)和(x2,y2)是Bessie 2D视野中第一个广告牌的左下角和右上角的坐标。下一行包含另外四个整数,类似地指定第二个广告牌的左下角和右上角。输入的第三行(也是最后一行)包含四个整数,指定卡车的左下角和右上角。所有坐标都在-1000到+1000的范围内。两个广告牌之间保证没有任何正面重叠的区域。

输出

请输出两个广告牌保持可见的总面积。

样例输入 

1 2 3 5
6 0 10 4
2 1 8 3
样例输出 
17
提示

【样例解释】

在这可见面积当中,5单位的面积来自第一个广告牌,12单位的面积来自第二个广告牌

思路点拨:首先我们设第一块广告牌为a,第二块广告牌为b,中间卡车面积为t,那么面积=a+b-at-bt.(at是a和t重叠的面积,bt是b和t重叠的面积)

那么主要就是求四个四边形面积;

所以可以写个函数。(human为结构体名)

int area(human a) {
    return  max(0,(a.x2-a.x1))*max(0,(a.y2-a.y1));
}

这里运用平面直角坐标系的知识求出面积,这里与0比较是为了避免未重叠的误算。

结构体为

struct human{
    int x1,y1,x2,y2;
};
但是a和b的两点已知,两块阴影部分未知,所以要求at.x1,at.x2,at.y1,at.y2,bt.x1,bt.x2,bt.y1,bt.y2

通过推导得出

at.x1=max(a.x1,t.x1);

at.x2=min(a.x2,t.x2)     

at.y1=max(a.y1,t.y1);

at.y2=min(a.y2,t.y2);

bt.x1=max(b.x1,t.x1);

bt.x2=min(b.x2,t.x2);

bt.y1=max(b.y1,t.y1);

bt.y2=min(b.y2,t.y2);

由此得出答案

#include<bits/stdc++.h>
using namespace std;
struct human{
    int x1,y1,x2,y2;
};
int area(human a) {
    return  max(0,(a.x2-a.x1))*max(0,(a.y2-a.y1));
}
int main(){
     human a,b,t,at,bt;
     cin>>a.x1>>a.y1>>a.x2>>a.y2;
     cin>>b.x1>>b.y1>>b.x2>>b.y2;
     cin>>t.x1>>t.y1>>t.x2>>t.y2;
     at.x1=max(a.x1,t.x1);
     at.x2=min(a.x2,t.x2);
     at.y1=max(a.y1,t.y1);
     at.y2=min(a.y2,t.y2);
     bt.x1=max(b.x1,t.x1);
     bt.x2=min(b.x2,t.x2);
     bt.y1=max(b.y1,t.y1);
     bt.y2=min(b.y2,t.y2);
     cout<<area(a)+area(b)-area(at)-area(bt);
    return 0;
}

举一反三

挡住的广告牌II

题目描述

奶牛贝西从她的牲口棚可以看到美丽的景色,她隔着马路看到两个广告牌,上面画着看起来很美味的牛饲料。不幸的是,其中一个广告牌最近被更换了,所以现在它的广告是“农夫拉里的割草机”。贝西不喜欢割草机,因为据她所知,割草机的唯一目的就是割掉她认为很好吃的草(如果你没有注意到,贝西的大部分思维过程都是围绕着食物的)。

幸运的是,剩余的奶牛饲料广告牌位于割草机广告牌的前面,可能挡住了一部分。

贝茜决心把那块令人讨厌的割草机广告牌完全从她的视线中移开,于是想出了一个危险的计划。她打算从谷仓里偷一块长方形的防水布,然后在深夜偷偷溜出去,盖住割草机广告牌的剩余部分,这样她就看不到任何部分了。

根据两个广告牌的位置,请帮助贝西计算出她需要的防水布的最小面积。由于谷仓里唯一可用的防水布是长方形的,贝西发现她需要的防水布的面积可能比割草机广告牌的暴露面积要略大一些,如下面的例子所示。防水布只能放置在与其他广告牌平行(即,则不能“倾斜”)。

输入

第一行输入包含四个空格分隔的整数:x1 y1 x2 y2,其中(x1,y1)和(x2,y2)是贝西视野中割草机广告牌左下角和右上角的坐标。下一行包含另外四个整数,类似地指定奶牛饲料广告牌的左下角和右上角。奶牛饲料的广告牌可能会掩盖割草机广告牌的全部或者部分,也可能完全没有遮住。所有坐标都在-1000到+1000之间。

输出

请输出防水布的面积。

样例输入 

2 1 7 4
5 -1 10 3
样例输出 

15
提示

在这里,奶牛饲料的广告牌遮住了割草机广告牌的右下角,但这并没有真正的帮助,因为贝西仍然需要使用一块防水布,其大小与整个割草机广告牌一样大.

奶牛洗牌

题目描述

农夫约翰深信快乐的奶牛会产出更多的牛奶,于是在他的谷仓里安装了一个巨大的迪斯科球,并计划教他的奶牛跳舞!

农夫约翰决定教他的牛跳“牛舞”。一开始他的N头奶牛(1≤N≤100)按一定顺序排成一排,然后进行3次“洗牌”,洗牌以后奶牛变成不同的顺序排列。为了让他的奶牛更容易找到自己的位置,农夫John用位置1…N标记了他的奶牛线的位置,所以队列中的第一头奶牛将在位置1,下一头奶牛将在位置2,以此类推,直到位置N。

洗牌的规则用N个数字a1…aN来描述,在洗牌过程中,处于i位置的奶牛移动到ai位置(因此,每个ai都在1…N的范围内)。在洗牌过程中,每头牛都会移动到它的新位置。幸运的是,所有的ai都是不同的,所以在洗牌时没有两头奶牛试图移动到相同的位置。

农民约翰的奶牛都被分配了不同的7位整数ID号。如果你在三次洗牌后被告知奶牛的顺序,请确定它们最初的顺序。

输入
第一行输入包含N,即奶牛的数量。下一行包含N个整数a1…aN。最后一行包含经过三次洗牌后的N头牛的顺序,每头牛由其ID号指定。
输出

N行输出,每行使用一个奶牛ID,按照在三次洗牌之前的顺序输出。

样例输入 
5
1 3 4 5 2
1234567 2222222 3333333 4444444 5555555
样例输出 

1234567
5555555
2222222
3333333
4444444

思路点拨:这一题注意是逆推,可以设两个数组np,op

np=新的奶牛的顺序,op=旧的奶牛的顺序

正推过程为1234567 5555555 2222222 3333333 4444444

1234567 4444444 5555555 2222222 3333333

1234567 3333333 4444444 5555555 2222222

1234567 2222222 3333333 4444444 5555555

得出逆推公式= op[j]=np[a[j]];

每次换完后都要将np[i]=op[i] 以便下一次逆推

样例代码

#include<bits/stdc++.h>
using namespace std;
int a[110];
int np[110];
int op[110];
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) {
        cin>>a[i];
    }
    for(int i=1;i<=n;i++) {
        cin>>np[i];
    }
    for(int i=1;i<=3;i++) {
        for(int j=1;j<=n;j++) {
            op[j]=np[a[j]];
        }
        for(int j=1;j<=n;j++) {
            np[j]=op[j];
        }
         
    }
    for(int i=1;i<=n;i++) {
        cout<<op[i]<<endl;
    }
    return 0;
}

牛奶测量

题目描述

农场主约翰买了三头奶牛: Bessie, Elsie, Mildred,每头奶牛最初每天产7加仑牛奶。众所周知,奶牛的产奶量可能会随着时间的推移而发生变化,因此,农场主约翰会在未来100天里定期进行测量,并把测量结果记在日志上。他的日志记录是这样的

35 Bessie -2

14 Mildred +3

第一个记录显示,第35天,Bessie的产奶量比上次测量时低了2加仑。下一项记录表明,在第14天,Mildred的牛奶产量比上次测量时增加了3加仑。农民约翰在任何一天最多只能做一次测量。不幸的是,他有点没有条理,并没有按时间顺序写下他的测量结果。为了让他的奶牛保持积极性,农场主约翰自豪地在他的谷仓的墙上展示当前牛奶产量最高的奶牛的照片(如果有几头奶牛并列出最高的牛奶产量,他就展示它们所有的照片)。请确定约翰需要多少天来更改这个展示。

输入

输入的第一行包含N,即约翰进行测量的次数。接下来的N行都包含一个度量值,按照上面的格式,指定一天(范围为1到100的整数)、奶牛的名称,以及自上次测量以来奶牛产奶量的变化(一个非零整数)。每头奶牛的产奶量总是在0..1000范围内。

输出

请输出约翰需要调整他的激励展示的天数(0..100范围内的整数)。

样例输入 
4
7 Mildred +3
4 Elsie -1
9 Mildred -1
1 Bessie +2
样例输出 

3

提示

【样例解释】
 

最初,所有的奶牛都有产奶量。第一天,Bessie的产奶量增加到9,这使她成为唯一的产奶量最高的奶牛,这也使得农场主约翰改变了他的展示方式。第四天,Elsie的产奶量减少到6,但这并不能改变Bessie是领头牛的事实。第7天,Mildred领先,更换了展示,第9天,Mildred的产量下降,与Bessie并列,再次更换了展示。

解析:

为了确定约翰需要多少天来更改展示,我们需要按照志记录计算每头奶牛的累计产奶量,并找出最高的产奶量。

根据日志记录,我们可以得到以下信息:

  • 第35天,Bessie的产奶量减少了2加仑。
  • 第14天,Mildred的产奶量增加了3加仑。

首先,我们需要初始化每头奶牛的初始产奶量为7加仑,并创建一个空的字典来存储每头奶牛的累计产奶量。

然后,我们按照日志记录的顺序更新每头奶牛的累计产奶量。对于每一条记录我们根据符号(+或-)来增加或少相应奶牛的产奶量。

最后,我们找出累计产奶量最高的奶牛(可能有多头),统计需要多少天来更改展示。具体步骤如下:

  1. 初始化每头奶牛的初始产奶量为7加仑。
  2. 创建一个空字典来存储每头奶牛的累计产奶量。
  3. 按照日志记录的顺序更新每头奶牛的累计产奶量:
    • 对于每一条记录,根据符号(+或-)来增加或减少相应奶牛的产奶量。
    • 将更新后的产奶量存储到字典中。
  4. 找出累计产奶量最高的奶牛(可能有多头):
    • 遍历字典,找到最高的产奶量。
    • 记录最高产奶量的奶牛(可能有多头)。
  5. 统计需要多少天来更改展示:
    • 统计日志记录的数量,即为需要的天数。

根据给定的日志记录,我们进行计算:

初始产奶量: Bessie: 7加仑 Elsie: 7加仑 Mildred: 7加仑

日志记录: 35 Bessie -2 14 Mildred +3

更新后的产奶量: Bessie: 5加仑 Elsie: 7加仑 Mildred: 10加仑

累计产奶量最高的奶牛是Mildred,产奶量为10加仑。

根据日志记录的数量,约翰需要2天来更改展示。

样例代码

#include<bits/stdc++.h>
using namespace std;
int a[110][110];
int b[110][110];
bool change(int c,int d){
    int maxn;
    maxn=max(b[0][d],max(b[1][d],b[2][d]));
    return maxn==b[c][d];
}
int main(){
    int cnt=0;
    int n;
    cin>>n;
    int date,ch,c;
    string name;
    for(int i=1;i<=n;i++) {
        cin>>date>>name>>ch;
        if(name=="Bessie") c=0;
        if(name=="Elsie") c=1;
        if(name=="Mildred") c=2;
        a[c][date]=ch;
    }
    for(int i=0;i<3;i++) {
        b[i][0]=7;
    }
    for(int i=1;i<=100;i++) {
        for(int j=0;j<3;j++) {
            b[j][i]=a[j][i]+b[j][i-1];
        }
    }
    for(int i=1;i<=100;i++) {
        if(change(0,i)!=change(0,i-1)||change(1,i)!=change(1,i-1)||change(2,i)!=change(2,i-1)) cnt++;
    }
    cout<<cnt;
    return 0;
}

  • 24
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值