蓝桥杯历届试题带分数解题报告---搜索 & 剪枝

版权声明:转载请注明出处:https://blog.csdn.net/qq1013459920 https://blog.csdn.net/qq1013459920/article/details/88072862

                                            历届试题 带分数  

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

问题描述

100 可以表示为带分数的形式:100 = 3 + 69258 / 714。

还可以表示为:100 = 82 + 3546 / 197。

注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。

类似这样的带分数,100 有 11 种表示法。

输入格式

从标准输入读入一个正整数N (N<1000*1000)

输出格式

程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。

注意:不要求输出每个表示,只统计有多少表示法!

样例输入1

100

样例输出1

11

样例输入2

105

样例输出2

6

很容易想到搜索的解法,但这题不能完全暴力,搜索过程需要剪枝:

由n = n1 + n2 / n3 得到:

1.n1 < n

2.n2 > n3

3.n2 % n3 == 0

在搜索过程用一个数组a[]记录区间每点取值

getVal()函数计算任意区间的值

addPath()函数判断所得数组是否存在n = n1 + n2 / n3情况

dfs()函数实现1~9全排列

AC Code: 

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
#define lowbit(x) x & -x;
const static int MAX_N = 1e6 + 5;
bool vis[15];
int a[15];
int n, res;
/*区间任意连续值*/
int getVal(int s, int e) {	
	int ret = 0;
	for (int i = s; i <= e; i++) {
		ret = ret * 10 + a[i];
	}
	return ret;
}
/*数组是否存在n = n1 + n2 / n3的区间分配方案*/
void addPath() {
	for (int i = 1; i <= 8; i++) {
		int n1 = getVal(1, i);
		if (n1 >= n) return;
		for(int j = i + 1 + (8 - i) / 2; j <= 8; j++){	
			/*
				n2的长度最少为剩余长度的一半(9 - (i + 1)) / 2
				否则 n2一定小于n3
			*/
			int n2 = getVal(i + 1, j);
			int n3 = getVal(j + 1, 9);
			if (n2 > n3 && n2 % n3 == 0 && n == n1 + n2 / n3) {
				res++;
			}
		}
	}
}
/*1~9全排列赋值数组a[]*/
void dfs(int s) {
	if (s == 10) {
		addPath();
		return;
	}
	for (int i = 1; i <= 9; i++) {
		if (!vis[i]) {
			a[s] = i;
			vis[i] = true;
			dfs(s + 1);
			vis[i] = false;
		}
	}
}
int main() {
	while (scanf("%d", &n) != EOF) {
		memset(vis, false, sizeof(vis));
		res = 0;	//方案数
		dfs(1);
		printf("%d\n", res);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq1013459920/article/details/88072862