*PAT_甲级_1044 Shopping in Mars (25分) (C++)【双指针】

目录

1,题目描述

题目大意

输入

 输出

说明

2,思路

核心思想

3,代码


1,题目描述

Sample Input 1:

16 15
3 2 1 5 4 6 8 7 16 10 15 11 9 12 14 13

 

Sample Output 1:

1-5
4-6
7-8
11-11

 

Sample Input 2:

5 13
2 4 5 7 9

 

Sample Output 2:

2-4
4-5

题目大意

在火星上购买商品(熟悉的设定),需要用一串钻石(每颗代表一定的价值)来支付,但每次支付需要截取连续的一段,且一旦截取后,就不能再恢复原状。

以题目所给例子为例,M$3, 2, 1, 5, 4, 6, 8, 7, and we must pay M$15,因此可以有三种方法:

  • 3, 2, 1, 5, 4, 6, 8, 7;
  • 3, 2, 1, 5, 4, 6, 8, 7;
  • 3, 2, 1, 5, 4, 6, 8, 7

输入

  1. 第一行:钻石数目N(<=10^5),支付的金额M(<=10^8);
  2. 第二行:钻石的价值(位置编号1-N);

 输出

  1. 所有可行的截取方案

说明

  • 若实在没有可以完全等于金额M的截取方法,则输出最小损失的截取方法 ;
  • Again all the solutions must be printed in increasing order of i:所有方案需按照编码的增序输出;
  • It is guaranteed that the total value of diamonds is sufficient to pay the given amount.:确保钻石总的价值超过需要支付的金额;

2,思路

这一题还是有点复杂的。这位大佬的方法讲的很详细!@日沉云起【pat甲级-1044-Shopping in Mars (25)】

这里借鉴大佬的第一种思路。时间复杂度为O(n).

核心思想

  • 设计左右两个指针i和j,在循环体中每次只移动一个
  • 当sum<M时,j右移
  • 当sum==M时,说明已找到完美方案,将minSum(存储最接近M的值)置为-1(这样就不会有比它更小的值了),并输出指针的位置(需要注意是否要减一);并将指针i右移
  • 当sum>M时,进一步判断minSum与sum的关系。若sum<minSum,说明有更接近M的答案,故重置minSum=sum,清空ans中的内容,并将当前左右指针存到ans中;若sum==minSum,将当前左右指针存入ans中。最后将指针i右移一位

 

3,代码

参考大神的第一种思路。

#include<iostream>
#include<vector>
#include<climits>
using namespace std;

int main(){
//#ifdef ONLINE_JUDGE
//#else
//    freopen("1.txt", "r", stdin);
//#endif

    int n, m;                                   //n钻石数目 m支付金额
    cin>>n>>m;

    int data[100001];
    for(int i = 1; i <= n; i++)
        scanf("%d", &data[i]);

    vector<pair<int, int>> ans;                 //当不存在完美方案时 保存所有额外开销最小的方案
    int sum = 0, minSum = INT_MAX;              //minSum用于判断距离m最近的值
    for(int i = 1, j = 1; i <= n && j <= n + 1;){   //当j超过n时 而i未超过 仍可以继续进入循环
        if(sum < m)
            sum += data[j++];

        else if(sum == m){
            printf("%d-%d\n", i, j-1);          //由于sum<m时 sum += data[j++] 所以当下一次sum==m时 j需要减一
            minSum = -1;                        //表示不可能再被超过
            sum -= data[i++];                   //sum已达到m i右移且j停止移动(相当于将链缩短)
        }

        else{
            if(sum < minSum){

                minSum = sum;
                ans.clear();                    //更新最小方案
                ans.push_back({i, j-1});        //由于sum<m时 sum += data[j++] 所以当下一次sum==m时 j需要减一
            }else if(sum == minSum){            //保留开销最小且相同的方案
                ans.push_back({i, j-1});
            }
            sum -= data[i++];                   //sum已达到m i右移且j停止移动(相当于将链缩短)
        }
    }

    if(minSum != -1){                           //未找到完美方案
        for(int i = 0; i < ans.size(); i++)
            printf("%d-%d\n", ans[i].first, ans[i].second);
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值