多校训练8 K Yet Another Problem About Pi 思维/贪心

Yet Another Problem About Pi

题意

题意:有一段 π km 长的行驶距离,在行驶图中用经纬线将地区划分成一个个区域,行驶的路线要求连续,可以是折线、曲线甚至闭合,问最多能通过多少个区域。

思路

思路:从题目易得,最少也可以经过四个区域,从一个点出发,我们可以移动微小的距离(小到不影响精度范围内,而且因为 π 是无理数,可以理解为其极后的一个数位发生了变动,可以不计)来直接访问周围的 4 个区域,显然,这是最优的。之后的路线我们可以选择沿 fi = min(w, d)到达一个新点,触发两个新区域,或者沿斜对角线 fj = sqrt(w × w + d × d)触发三个新区域。在这两种路线的选择上,最优解就是在满足 i × fi + j × fj <= pi 中找 2 × i + 3 × j 最大,用max函数不断更新最大值ans,for循环能开到最大能开到1000,因为T的范围最大到 1 0 5 10 ^5 105

做法

思维

  • 不清醒,把ans设成了double…wa死了
  • 在两种情况的for循环中,注意 i 要从 0 开始。
    for(int i = 0; i <= 1000; i++)
  • 或者不用 if,直接两次for循环找最优解,也可以在一次for循环里完成。
ans = 0;
cin>>w>>d;
fi = min(w, d);
fj = sqrt(w * w + d * d);
for(int i = 0; i <= 100; i++)
{
    if(pi - fi * i > 0) ans = max(ans, (int)((pi - i * fi) / fj) * 3 + 2 * i);
    if(pi - fj * i > 0) ans = max(ans, (int)((pi - i * fj) / fi) * 2 + 3 * i);
} 
cout<<ans + 4<<endl;

accode:

#include <bits/stdc++.h>
#define ios std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
using namespace std;
typedef long long ll;
#define pi acos(-1.0)

int main()
{
    ios
    int T;
    double w, d, fi, fj;
        int ans;
    cin>>T;
    while(T--)
    {
        ans = 4;
        cin>>w>>d;
        fi = min(w, d);
        fj = sqrt(w * w + d * d);
        if(fi / 2 > fj / 3)//获得同样收益时走斜对角线用的线少
        {
            for(int i = 0; i <= 1000; i++)
            {
                if(fi * i > pi)   break;
                int j = (pi - i * fi) / fj;
                ans = max(ans, 2 * i + 3 * j + 4); 
            }
        }
        else
        {
            for(int i = 0; i <= 1000; i++)
            {
                if(fj * i > pi)    break;
                int j = (pi - fj * i) / fi;
                ans = max(ans, 3 * i + j * 2 + 4);
            }
        }
        cout<<ans<<endl;
    }
    
    return 0;
}

贪心

用贪心思想理解:一样先按照区域/代价比最优先选择方案,①如果选的是方案 1 走短边,那么在最后一次选择行驶方向时,看看是否能放弃短边,最后一次的短边长 fi 加上剩余的距离 pi - i × fi 看是否能改成走斜对角线,这样可以多增加一个区域。②如果选的是方案2走斜对角线,那么在最后一次选择行驶方向时,看看是否能放弃走斜对角线,将剩余的距离 pi - i × fj 改成走两次短边,这样可以增加一个区域。

accode:

#include <bits/stdc++.h>
#define ios std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
using namespace std;
typedef long long ll;
#define pi acos(-1.0)

int main()
{
    ios
    int T;
    double w, d, fi, fj;
    int ans;
    cin>>T;
    while(T--)
    {
        ans = 4;
        cin>>w>>d;
        fi = min(w, d);
        fj = sqrt(w * w + d * d);
        if(fi > pi)
        {
            cout<<ans<<endl;
        }
        else
        {
            if(fi / 2 < fj / 3)
            {
                int i = pi / fi;
                ans += i * 2;
                if(pi - (i-1) * fi > fj) ans++;
            }
            else
            {
                int i = pi / fj;
                ans += i * 3;
                if(pi - i * fj > fi) ans += 2;
                else if(pi - (i-1) * fj > 2 * fi)   ans++;
            }
            cout<<ans<<endl;
        }        
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值