原题链接
题目大意
有 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 6≤N≤20000。
解题思路
本题可以用
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 po−5,ne+5。
[2] 4正1反,翻过来后 p o − 3 , n e + 3 po-3,ne+3 po−3,ne+3。
[3] 3正2反,翻过来后 p o − 1 , n e + 1 po-1,ne+1 po−1,ne+1。
[4] 2正3反,翻过来后 p o + 1 , n e − 1 po+1,ne-1 po+1,ne−1。
[5] 1正4反,翻过来后 p o + 3 , n e − 3 po+3,ne-3 po+3,ne−3。
[6] 0正5反,翻过来后 p o + 5 , n e − 5 po+5,ne-5 po+5,ne−5。
在这里,你们可以慢慢消化,最好是拿一张纸自己枚举一下这 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
5−i。由于反面的硬币要翻成正面的,正面的硬币要翻成反面的,所以正面硬币的增值为
(
5
−
i
)
−
i
(5-i)-i
(5−i)−i。最后,按照正面朝上的硬币个数去重,我们就可以切掉此题。
注意事项:
1.上面的那 6 6 6种翻硬币情况,一定要搞清楚,不然很容易做错。
2.正面硬币的增值为 ( 5 − i ) − i (5-i)-i (5−i)−i,是因为反面的翻过来增加了 ( 5 − i ) (5-i) (5−i)个,而又有正面的翻过去减少了 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 ∼