蓝桥杯刷题——娜神平衡(状态搜索)

1,289 阅读2分钟

「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战」。

这是蓝桥杯刷题训练里面的一道题,主要包含了状态搜索(也有其他的做法)。

题目

给定一些数,每次只能对这些数中的一个数操作,将这个数分到A组或者B组,每次操作结束后,要求A组和B组之间的差不超过一个数r,直到最后这些数全部分完。最后分别从小到大输出A组和B组。并且要求第一个数必须分到A组。 输入n,表示n个数,输入r表示不能超过的那个数。 再输入n个数。

输出是输出两个组的数。

思路

我们一般的想法可能是一个数一个数的找,而由于每次操作完一个数后都要比较一次,所以这种搜索的效率实在是比较低,而且算法的设计也不好设计。我们不妨换个思路,先找到最终结果的所有情况。对这些情况一个个去遍历,然后去判断,观察是否符合题干要求,如果符合的话就可以直接输出了。因为这道题最终是一定有解的,从所有的情况中一个个去找,一定可以找到答案的。而如何存储所有的情况呢,这里就可以用到状态压缩了,将这些数用独一无二的二进制数来表示,遍历二进制数的时候,是1的位子就分到A组,是0的位子就分到B组。题干中还有一个要求是第一个数必须分到A组,那么我们提前把第一个数选出分给A组即可,状态搜索的流程还是一样的。

代码

#include<bits/stdc++.h>
using namespace std;
int N[100086],val1[100086],val2[100086];
int n,r,idx1,idx2;
bool check(){
    int x=0,y=0,sum1=0,sum2=0,flag=1;
    sum1=val1[++x];
    while(abs(sum1-sum2)<=r&&flag){
        flag=0;
        if(abs(sum1+val1[x+1]-sum2)<=r&&x+1<=idx1){
            x++;
            flag=1;
            sum1+=val1[x];
        }
        if(abs(sum1-val2[y+1]-sum2)<=r&&y+1<=idx2){
            y++;
            flag=1;
            sum2+=val2[y];
        }
    }
    if(x==idx1&&y==idx2){
        return true;
    }
    return false;
}
int main(){
    cin>>n>>r;
    for(int i=0;i<n;i++){
        cin>>N[i];
    }
    int first=N[0];
    sort(N,N+n);
    for(int i=1;i<(1<<n)-1;i++){//这里去掉两种情况,就是全部在一个组的情况。这种情况肯定是不出在的
        int judge=0;
        idx1=idx2=0;
        memset(val1,0,sizeof(val1));
        memset(val2,0,sizeof(val2));
        for(int j=0;j<n;j++){
            if((1<<j)&i){
                val1[++idx1]=N[j];
            }
            else{
                val2[++idx2]=N[j];
            }
        }
        if(check()){
            for(int j=1;j<=idx1;j++){
                if(val1[j]==first)//第一个数在哪,谁就是A组
                    judge=1;
            }
            if(judge){
                for(int j=1;j<=idx1;j++){
                    cout<<val1[j]<<' ';
                }
                cout<<endl;
                for(int j=1;j<=idx2;j++){
                    cout<<val2[j]<<' ';
                }
                cout<<endl;
            }
            else{
                for(int j=1;j<=idx2;j++){
                    cout<<val2[j]<<' ';
                }
                    cout<<endl;
                for(int j=1;j<=idx1;j++){
                    cout<<val1[j]<<' ';
                }
                    cout<<endl;
            }
            break;
        }
    }
    return 0;
}