SSL1457 翻币问题


原题链接

SSL1457 外网进不去

题目大意

N N N个硬币全部正面朝上排成一排,每次将其中 5 5 5个硬币翻过来放在原位置,直到最后全部硬币翻成反面朝上为止。试编程找出步数最少的翻法,输出最少步数及翻法。

输入格式

从键盘输入一个正整数 N N N,表示硬币的数量。

输出格式

一个整数,表示最少步数

S a m p l e \mathbf{Sample} Sample I n p u t \mathbf{Input} Input

6

S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output

6

H i n t & E x p l a i n \mathbf{Hint\&Explain} Hint&Explain
翻硬币步骤如下:*为反面,1为正面

0 : 111111
1 : 1*****
2 : *1111*
3 : 1***11
4 : **11**
5 : 111*11
6 : ******

数据范围

对于 100 % 100\% 100%的数据满足: 6 ≤ N ≤ 20000 6≤N≤20000 6N20000

解题思路

本题可以用 b f s bfs bfs解决。
我们先考虑随意翻 5 5 5个硬币,情况会有多少种。
枚举出来后,我们发现,有下面这几种情况:

设硬币正面朝上的个数是 p o po po,反面朝上的个数为 n e ne ne
[1] 5正0反,翻过来后 p o − 5 , n e + 5 po-5,ne+5 po5,ne+5
[2] 4正1反,翻过来后 p o − 3 , n e + 3 po-3,ne+3 po3,ne+3
[3] 3正2反,翻过来后 p o − 1 , n e + 1 po-1,ne+1 po1,ne+1
[4] 2正3反,翻过来后 p o + 1 , n e − 1 po+1,ne-1 po+1,ne1
[5] 1正4反,翻过来后 p o + 3 , n e − 3 po+3,ne-3 po+3,ne3
[6] 0正5反,翻过来后 p o + 5 , n e − 5 po+5,ne-5 po+5,ne5

在这里,你们可以慢慢消化,最好是拿一张纸自己枚举一下这 6 6 6种情况,再继续往下看。

枚举完这 6 6 6中情况过后,我们就可以进行 b f s bfs bfs了。
我们发现,在上面 6 6 6中情况中,正面朝上的硬币数量是一定在 1 1 1 5 5 5之间徘徊的,因此我们可以循环要翻的正面朝上的硬币个数,并设这个数为 i i i,那么可以得出,反面的硬币数量为 5 − i 5-i 5i。由于反面的硬币要翻成正面的,正面的硬币要翻成反面的,所以正面硬币的增值为 ( 5 − i ) − i (5-i)-i (5i)i。最后,按照正面朝上的硬币个数去重,我们就可以切掉此题。

注意事项:

1.上面的那 6 6 6种翻硬币情况,一定要搞清楚,不然很容易做错。
2.正面硬币的增值为 ( 5 − i ) − i (5-i)-i (5i)i,是因为反面的翻过来增加了 ( 5 − i ) (5-i) (5i)个,而又有正面的翻过去减少了 i i i个。不要写成一些乱七八糟的东西。


最后,祝大家早日
请添加图片描述

上代码

我这里做的代码是本来有输出每一步有多少个硬币在正面,只不过被我注释掉了,如果想要看可以自行把注释去掉。

#include<iostream>
#include<vector>
#include<queue>

using namespace std;

struct obj{
    obj(int a=0,int b=0):positive(a),tot_step(b){}
    vector<int> steps;
    int positive,tot_step;
};

queue<obj>       q;
bool             a[20010];
int              n;

int main()
{
    cin>>n;
    obj st=obj(n,0);
    st.steps.push_back(n);
    a[n]=true;
    q.push(st);
    while(q.size())
    {
        obj now=q.front();
        q.pop();
        int positive=now.positive;
        int tot_step=now.tot_step;
        // cout<<positive<<" "<<n-positive<<endl;
        vector<int> steps=now.steps;
        if(positive==0)
        {
            cout<<tot_step<<endl;
            // for(int i=0; i<steps.size(); i++)
            //     cout<<i<<":"<<steps[i]<<endl;
            return 0;
        }
        for(int i=0; i<=5; i++)
        {
            if(positive<i||n-positive<5-i)
                continue;
            int next_state=positive-i+(5-i);
            // cout<<"\t"<<next_state<<endl;
            if(a[next_state])
                continue;
            a[next_state]=true;
            obj temp=obj(next_state,tot_step+1);
            temp.steps=steps;
            temp.steps.push_back(next_state);
            q.push(temp);
        }
    }
    return 0;
}

完美切题 ∼ \sim

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值