蓝桥杯 ALGO-998 娜神平衡(简单粗暴)

试题 算法训练 娜神平衡

资源限制

时间限制:1.0s 内存限制:256.0MB

问题描述

  娜娜是一个特别可爱的女孩子,作为学神的她最近在情感方面出现了一点点小问题。
  她暗恋的琦琦是一名学霸,他只喜欢长得漂亮和学习很好的女生。
  娜娜学习确实很神,但是她在琦琦面前却总是表现不出平时的神力。
  琦琦感受到了娜娜对他的爱,但是他还是觉得娜娜的学习并不是特别好,于是他出了一道题给娜娜。
  “娜娜,我们之间的关系需要在不断深入的同时保持一定的平衡,不可以你总是强势或者我总是弱势。”
  琦琦给了娜娜一些两两不等的数,希望娜娜能把这些数分成两组A和B,满足以下条件:
  1:每一次只能操作一个数,即只取出一个数分入A中或B中;
  2:每一次操作完成后,A中数之和与B中数之和的差不能超过r。
  新时代的丘比特们啊,帮帮娜娜吧!(笑)

输入格式

  输入共两行。
  第一行包括两个正整数n和r,n表示琦琦一共给了n个数,r的意义见题目描述。
  第二行包括n个正整数,分别表示琦琦给的n个数。

输出格式

  输出共两行,分别把A与B两组数按从小到大输出。
  注意输入中n个数的第一个必须分入A组。
  琦琦保证这样的输出唯一。

样例输入

4 10
9 6 4 20

样例输出

4 6 9
20

样例说明

  先把4和6先后分入A组,再把20分入B组,最后把9分入A组。

数据规模和约定

  很小,真的很小。(题目没明写,我查数据集只有: 1 <= n <= 10)


简单粗暴的思路:

  1. 排列后,按顺序将数优先放入A中,放进,记录
  2. A中放不进,放B中,放进,记录
  3. B中放不进,数据放回队尾,下次再枚举
  4. 按照记录的顺序回溯,将最后一次放入数组中的元素删除,放回队尾,下次再枚举
  5. 循环直到队列没有元素枚举

要点:

  1. 排序数据,便于枚举判断
  2. 使用队列存储数据,枚举失败的数据可以放回队尾,下次再枚举
  3. 使用栈存储枚举成功的顺序,便于回溯(正因为把顺序保存了下来,免于用递归)
  4. 题目要求第一个数只能放在A中,因此,只要发现B中存在第一个数,就把B当成A就行了(由答案的唯一性,可以知道一个组中的数永远待在一起,因此只要把存有第一个数的组当成A就可以了,没必要纠结于优先枚举进哪个数组)

代码:

#include <bits/stdc++.h>

using namespace std;
const int N = 110;
int q[N], first;

vector<int> a, b, pre;
int n, m, sa, sb;

int main(){
    scanf("%d%d", &n, &m);
    
    for (int i = 0 ;i < n; i ++) scanf("%d", &q[i]);

    first = q[0];	//保存第一个数,根据题意是一定要存进A里的
    
    sort(q, q + n);		//排序,从小到大地枚举,关键
    
    int hh = 0, tt = n - 1;		//模拟队列
    
    while (hh <= tt){	//队列为空,枚举完成
        int t = q[hh ++];
        sa += t;
        a.push_back(t);		//枚举的顺序是优先把小的数放进A
        pre.push_back(1);	//存储已经成功枚举的顺序, 1表示存进了A,2表示存进了B
        if (abs(sa - sb) > m){		
            sa -= t;
            a.pop_back();	//超过限制,选不了
            pre.pop_back();	
            sb += t;
            b.push_back(t);		//存进B
            pre.push_back(2);

            if (abs(sa - sb) > m){
                sb -= t;
                b.pop_back();		//超过限制,选不了
                pre.pop_back();
                q[++ tt] = t; //目前,两组都无法放这个数,将这个数存回队列,下次再枚举
                if (pre.back() == 1) q[++ tt] = a.back(), a.pop_back(), pre.pop_back();	//之前某个数放错了,撤销式地回溯,放入队列,下次再枚举
                else q[++ tt] = b.back(), b.pop_back(), pre.pop_back();
            }
        }
    }
    
    sort(a.begin(), a.end());	//排序答案,题目要求
    sort(b.begin(), b.end());
    
    for (int i = 0 ; i < b.size(); i ++)  //若题目要求的第一个数在B中,则替换AB数组,保证第一个数在A中
        if (b[i] == first){
            swap(a, b);
            break;
        }
    
    for (int i = 0 ; i < a.size(); i ++) printf("%d ", a[i]);
    puts("");
    for (int i = 0 ; i < b.size(); i ++) printf("%d ", b[i]);
    
    return 0;
}

截图

吐槽:

这题应该不算难(毕竟我都会),看到其他人有用状态压缩和dfs的,我发现我的思路挺简单粗暴的,就想分享一下。

嗷,80分没过最后一个数据的,不是因为题目有问题,而是题意要求第一个数据必须在A中。

posted @ 2022-02-11 23:05  mosqu1to  阅读(776)  评论(0编辑  收藏  举报