蓝桥杯练习系统历届试题 带分数 dfs

问题描述

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
 
首先是暴力,TLE ,33分,讲道理我还想不到好嘛。
 1 // 纯纯的暴力 挂了。
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <iostream>
 5 using namespace std;
 6 
 7 int vis[10], visall[10];
 8 
 9 bool check(int num) {
10     while(num) {
11         int temp = num % 10;
12         if (vis[temp]) return false;
13         if (temp == 0) return false;
14         vis[temp]++;
15         num /= 10;
16     }
17     return true;
18 }
19 
20 bool checkAll() {
21     for (int i=1; i<10; ++i) {
22         if (vis[i] != 1) return false;
23     }
24     return true;
25 }
26 
27 void copyNum(int a[], int b[]) {
28     for (int i=1; i<10; ++i) {
29         a[i] = b[i];
30     }
31 }
32 
33 int main() {
34     int n;
35     while(cin >> n) {
36         memset(vis, 0, sizeof(vis));
37         memset(visall, 0, sizeof(visall));
38         int ans = 0;
39 
40         for (int l=1; l<n; ++l) {
41             memset(vis, 0, sizeof(vis));
42             if (!check(l)) continue;
43             copyNum(visall, vis);
44 
45             for (int down=1; down<100000; ++down) {
46                 int up = (n-l) * down;
47                 if (down > up) continue;
48                 if (up % down) continue;
49                 copyNum(vis, visall);
50                 if (!check(down) || !check(up)) {
51                         continue;
52                 }
53                 if (checkAll())  {
54                     //cout << l << " " << down << " " << up << endl;
55                     ans++;
56                 }
57             }
58         }
59 
60         cout << ans << endl;
61     }
62     return 0;
63 }
View Code

然后是优化。依然感觉dfs好神奇的说。

 1 /*
 2  刚才暴力的优化吧。
 3  先遍历左边的数字,然后dfs搜分母对应的长度 和 数字。
 4  */
 5 
 6 #include <stdio.h>
 7 #include <string.h>
 8 #include <iostream>
 9 using namespace std;
10 
11 int lens, v, ans;
12 int vis[10], visall[10];
13 
14 bool check(int num) {
15     int k = 0;
16     while(num) {
17         int temp = num % 10;
18         if (vis[temp]) return false;
19         vis[temp]++;
20         k++;
21         num /= 10;
22     }
23     lens = 9-k; // 剩余可用数字的个数
24     return true;
25 }
26 
27 void copyVis() {
28     for (int i=0; i<10; ++i) {
29         visall[i] = vis[i];
30     }
31 }
32 
33 int judge(int up) { // fenmu
34     int k = 0;
35     copyVis();
36     while(up) {
37        int temp = up % 10;
38        if (visall[temp]) return -1;
39        visall[temp] = 1;
40        k++;
41        up /= 10;
42     }
43     return k;
44 }
45 
46 void dfs(int len, int val) { // len fenzi
47     if (len > lens/2) return;
48     if (judge(v*val) == lens-len) ans++;
49     for (int i=1; i<10; ++i) {
50         if (vis[i]) continue;
51         vis[i] = 1;
52         dfs(len+1, val*10+i);
53         vis[i] = 0;
54     }
55 }
56 
57 
58 
59 int main() {
60     int n;
61     while(cin >> n) {
62         ans = 0;
63         for (int l=1; l<n; ++l) {
64             memset(vis, 0, sizeof(vis));
65             vis[0] = 1;
66             if (!check(l)) continue;
67             v = n - l;
68             dfs(0, 0); // len fenmu
69         }
70         cout << ans << endl;
71     }
72     return 0;
73 }
View Code

然后还有一种思路就是,对九个数字实现全排列,然后从八个空里找两个放+ 和 /。讲道理,这样的话,时间复杂度是10^6*8*7 不知道能不能过.....

原文地址:https://www.cnblogs.com/icode-girl/p/5251780.html