7-2 芬兰木棋

文章描述了一种基于芬兰木棋游戏的算法问题,玩家哲哲需在固定位置投掷木棋击倒其他木棋以得分。游戏规则被简化并加入了赛博朋克元素,允许哲哲控制击倒木棋的数量(k)。问题在于求解哲哲最多能得多少分,并在达到最高分的情况下最少需要投掷多少次。输入包括木棋的位置和分数,输出是最高分和最少投掷次数。解决方案涉及对木棋位置按斜率排序,使用地图数据结构存储并处理,最终计算总分和投掷次数。
摘要由CSDN通过智能技术生成

芬兰木棋(Mölkky,又称芬兰木柱)是源自芬兰的一项运动。哲哲将这个运动改造成了赛博朋克单人版,现在场上一开始有 N 根立起的小木棋(上面分别标有一个非负整数),哲哲投掷一根大木棋去击倒这些小木棋以获得分数。分数规则如下:

  • 如果仅击倒 1 根木棋,则得木棋上的分数。
  • 如果击倒 2 根或以上的木棋,则只得击倒根数的分数。(例如击倒 5 根,则得 5 分。)

哲哲固定站在 (0,0) 点上,四周放着若干个小木棋 (Xi​,Yi​),坐标均为整数。每次哲哲可以朝一个方向扔出大木棋,大木棋会打倒这个方向上离哲哲最近的 k 个小木棋。哲哲游戏水平很高超,所以这个 k 可以自由控制。

请问哲哲最多能拿多少分,在获得最多分数的情况下最少需要扔出多少次大木棋?

规则与真实规则有较大出入,真实游玩时请以国际莫尔基组织的规则为准

输入格式:

输入第一行是一个正整数 N (1 ≤ N ≤ 105),表示场上一开始有 N 个木棋。

接下来 N 行,每行 3 个整数 Xi​,Yi​,Pi​,分别表示木棋放置在 (Xi​,Yi​),木棋上的分数是 Pi​。坐标在 32 位整数范围内,分数为小于等于 1000 的正整数。

保证 (0,0) 点没有木棋,也没有木棋重叠放置。

输出格式:

输出一行两个数,表示最多分数以及获得最多分数最少需要投掷大木棋多少次。

输入样例:

11
1 2 2
2 4 3
3 6 4
-1 2 2
-2 4 3
-3 6 4
-1 -2 1
-2 -4 1
-3 -6 1
-4 -8 2
2 -1 999

输出样例:

1022 9
思路

首先根据不同的斜率进行排序

可以用map来枚举每种不同的斜率

由于精度问题,可以存x,y坐标来存

如果出现两个连续的1,就只需要扔一次

否则,扔两次

最终结果的最大值是总和

代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>

using namespace std;

typedef long long ll;
typedef pair<int,int> PII;

map<PII,vector<pair<ll,int>>> mp;
int n,s;
ll x,y;

int main()
{
    cin>>n;
    int sum=0,cnt=0;
    for(int i=0;i<n;i++)
    {
        cin>>x>>y>>s;
        sum+=s;
        ll d=x*x+y*y;
        ll c=abs(__gcd(x,y));
        x/=c,y/=c;
        mp[{x,y}].push_back({d,s});
    }
    for(auto x:mp)
    {
        vector<pair<ll,int>> v=x.second;
        sort(v.begin(),v.end());
        for(int i=0;i<v.size();i++)
        {
            if(v[i].second!=1) cnt++;
            else if((v[i+1].second!=1&&i+1<v.size())||i+1==v.size()) cnt++;
        }
    }
    cout<<sum<<' '<<cnt;
    return 0;
}

注意点:学会使用map来进行枚举和排序 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值