[BFS]翻币问题

翻币问题

Description

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


Input

从键盘输入一个正整数N(6<=N<=20000),表示硬币的数量。


Output

第1行:一个整数,表示最少步数
第2行至最后一行:先是一个整数,表示步骤序号(从0开始编号),后接一个":",再接当前硬币的状态(用一个整数表示正面朝上的硬币的个数)


Sample Input

6


Sample Output

6


解析

任意翻转5个硬币,正反面的个数变化为:
5正0反 正-5 反+5
4正1反 正-3 反+3
3正2反 正-1 反+1
2正3反 正+1 反-1
1正4反 正+3 反-3
0 正5反 正+5 反-5
即有6种变化,用state[i]表示节点i正面的个数,完成翻转即正面的个数为0,在执行上面6种翻转时要检查是否符合翻条件,即正面的个数和反面的个数要大于其对应的翻转数,生成新节点时要判断此节点是否出现过,否则就会出现相同的5个硬币翻来翻去的情况。


代码

#include<stdio.h>
#include<iostream>
using namespace std;
int n,a[20005],fa[20005],t[20005],ans[20005];
void bfs(){
	int head=0,tail=1;
	a[1]=n;fa[1]=0;ans[1]=0;
	do{
		head++; 
		for(int i=0;i<=5;i++){ //六种可能
			if(a[head]>=i and n-a[head]>=5-i){ //条件判断
				tail++;
				ans[tail]=ans[head]+1;
				a[tail]=a[head]-i+5-i;
				fa[tail]=head;
				if(!t[a[tail]])t[a[tail]]=1; //如果没翻过,就标记
				 else tail--; 
				 if(a[tail]==0){
					printf("%d",ans[tail]);
					return ;
				}
			}
		}
	}while(head<=tail);
}
int main(){
	scanf("%d",&n);
	bfs();
	return 0;
}
posted @ 2019-12-06 21:40  学校开除后  阅读(236)  评论(0编辑  收藏  举报