版权声明:转载请注明出处: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;
}