✍个人博客:https://blog.csdn.net/Newin2020?spm=1011.2415.3001.5343
📚专栏地址:蓝桥杯题解集合
📝原题地址:带分数
📣专栏定位:为想参加蓝桥杯的小伙伴整理常考算法题解,祝大家都能取得理想成绩!
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
问题描述
100 可以表示为带分数的形式:100=3+69258/714
还可以表示为:100=82+3546/197
注意特征:带分数中,数字 1∼9 分别出现且只出现一次(不包含 0)。
类似这样的带分数,100 有 11 种表示法。
输入格式
一个正整数。
输出格式
输出输入数字用数码 1∼9 不重复不遗漏地组成带分数表示的全部种数。
数据范围
1≤N<106
输入样例1:
100
输出样例1:
11
输入样例2:
105
输出样例2:
6
暴力法
#include <bits/stdc++.h>
using namespace std;
int n;
const int N = 10;
int res[N]; //存储结果
bool st[N]; //表示元素是否用过
int cnt = 0;
//计算每一段的总数
int calc(int l, int r) {
int num = 0;
for (int i = l; i <= r; i++) {
num = num * 10 + res[i];
}
return num;
}
//将全排列的数组分成三段进行判断
void dfs(int k) {
if (k == 9) {
for (int i = 0; i < 7; i++) {
for (int j = i + 1; j < 8; j++) {
int a = calc(0, i);
int b = calc(i + 1, j);
int c = calc(j + 1, 8);
if (a * c + b == n * c) //c++中除法是整除,所以要转换为乘法
cnt++;
}
}
return;
}
//进行全排列
for (int i = 1; i <= 9; i++) {
if (!st[i]) {
st[i] = true;
res[k] = i;
dfs(k + 1);
st[i] = false;
}
}
}
int main() {
cin >> n;
dfs(0);
cout << cnt << endl;
return 0;
}
暴力法(内置函数)
next_permutation() 蓝桥杯允许使用
#include<bits/stdc++.h>
using namespace std;
int n;
const int N=10;
int res[N]; //存储结果
int cnt=0;
//计算每一段的总数
int calc(int l,int r)
{
int num=0;
for(int i=l;i<=r;i++)
{
num=num*10+res[i];
}
return num;
}
int main()
{
cin>>n;
for(int i=0;i<9;i++)
res[i]=i+1;
do{
for(int i=0;i<7;i++)
{
for(int j=i+1;j<8;j++)
{
int a=calc(0,i);
int b=calc(i+1,j);
int c=calc(j+1,8);
if(a*c+b==n*c)
cnt++;
}
}
}while(next_permutation(res,res+9)); //调用函数进行全排列
cout<<cnt<<endl;
return 0;
}
优化
先枚举 a ,再枚举 c ,直接通过 a 和 c 求出 b ,就不用再枚举 b 了。然后判断 b 是否满足要求,如果 b 中的每一位都没有被 a 和 c 所用过并且 1 到 9 都被已经用过了,则满足要求,答案总数加 1。
举个例子,假设 a 枚举到了 82,然后枚举 c,而 c 枚举到了 3456,则去计算 b,根据公式推导,b 等于 n*c-a*c
,从而算出 197。接下来就进行判断,首先 abc 都不能为 0 这是肯定的,然后需要判断 b 是否用了剩下没有用过的数字,如果出现了 a 和 c 中的数字则不满足条件,并且 b 要将剩下没用过的数字全部用上才满足条件。
#include <bits/stdc++.h>
using namespace std;
const int N = 10;
int n, ans = 0;
bool st[N], backup[N];
//判断是否满足条件
bool check(int a, int c) {
//计算b
//这里需要long long是因为防止n为10的6次方时与c相乘后爆int,导致b为负数,x也会为负数
//x为负数的话,backup就会数组越界,所以要加long long
long long b = n * (long long)c - a * c;
//a,b,c都不能为0
if (!b || !a || !c)
return false;
//因为原状态数组不能改变,为了后续判断,就新建一个状态数组用于判断
memcpy(backup, st, sizeof(st));
//判断b中的每一位数字
while (b) {
int x = b % 10;
if (!x || backup[x])
return false;
b /= 10;
backup[x] = true;
}
//判断是否1-9都使用过
for (int i = 1; i <= 9; i++) {
if (!backup[i])
return false;
}
return true;
}
//枚举c
void dfs_c(int x, int a, int c) {
if (x > 9)
return;
if (check(a, c))
ans++;
for (int i = 1; i <= 9; i++) {
if (!st[i]) {
st[i] = true;
dfs_c(x + 1, a, c * 10 + i);
st[i] = false;
}
}
}
//枚举a
void dfs_a(int x, int a) {
if (a >= n)
return;
if (a)
dfs_c(x, a, 0);
for (int i = 1; i <= 9; i++) {
if (!st[i]) {
st[i] = true;
dfs_a(x + 1, a * 10 + i);
st[i] = false;
}
}
}
int main() {
cin >> n;
dfs_a(0, 0);
cout << ans << endl;
return 0;
}