zoukankan      html  css  js  c++  java
  • AcWing 带分数 dfs

    方法一:

    最原始,最暴力,耗时4秒,但是是最好想的思路。

    生成1~9的全排列。对于每个全排列,依次枚举a,b,c的位数。枚举三个数的位数时,就相当于在9个数形成的8个空里,插入俩隔板。

    所以时间复杂度大致是全排列个数9!乘以8个空里选俩的组合数:c(8,2)。

    估计是10,160,640。不过按电脑1秒计算量是10^7看的话,运行4秒大致时间复杂度是4*10^7左右。‬

    能得出正确答案,不过绝对会超时。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int n, ans;
     4 int a[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
     5 int getNum(int l, int r) { //求出这个数
     6     int res = 0;
     7     for (int i = l; i <= r; i++) {
     8         res = res * 10 + a[i];
     9     }
    10     return res;
    11 }
    12 bool check(int a, int b, int c) { //判断n == a + b / c
    13     if (b % c != 0) {
    14         return false;
    15     }
    16     if (a + b / c != n) {
    17         return false;
    18     }
    19     return true;
    20 }
    21 int main() {
    22     cin >> n;
    23     do {
    24         for (int i = 0; i <= 6; i++) { 
    25             for (int j = i + 1; j <= 7; j++) { // c必须大于0,所以要给c留出一位
    26                 int a = getNum(0, i);
    27                 int b = getNum(i + 1, j);
    28                 int c = getNum(j + 1, 8);
    29                 if (check(a, b, c)) {
    30                     ans++;
    31                 }
    32             }
    33         }
    34     } while (next_permutation(a, a + 9));
    35     cout << ans << endl;
    36     return 0;
    37 }

    方法二:

    优化版。1.2秒左右,按理说还是会超时,不过是目前为止的最优解。

    方法一中是直接枚举a,b,c的位数,自变量是三个,没有用到题目给出的性质。

    方法二把等式n = a + b / c两边乘上c,得c * n = c * a + b。

    n是给出的,枚举a和c就好,b可以直接算出,自变量是两个了。

    n最多只有7位。

    搜索思路:

      先枚举a,对于每个枚举的a再枚举c,最后再判断等式是否成立。就是递归搜索a时在每一个递归搜索树的叶子节点后再接上另一个递归搜索树用来递归搜索c,然后在这个树的叶子节点上判断一下等式是否成立。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 20; 
     4 typedef long long ll;
     5 int n;
     6 int ans;
     7 bool st[N], bk[N]; //判重数组和备份数组 
     8 bool check(int a, int c) { //判断a和c是不是满足要求
     9      ll b = (ll)c * n - (ll)c * a; 
    10      if (!a || !b || !c) { //a,b,c不能为0 
    11          return false;
    12      }
    13      memcpy(bk, st, sizeof st); //把st复制给bk
    14      while (b) { //拆出b的每一位 
    15          int x = b % 10;
    16         b /= 10;
    17         if (!x || bk[x]) { //如果x为0或者x已经出现过,就不合法 
    18             return false;
    19         }
    20         bk[x] = true;
    21      } 
    22      for (int i = 1; i <= 9; i++) { //判断9个数是不是全都出现过 
    23          if (!bk[i]) { 
    24              return false;
    25          }
    26      }
    27      return true;
    28 }
    29 void dfs_c(int u, int a, int c) {
    30     if (u == n) { //如果已经用完了n个数字 
    31         return;
    32     }
    33     if (check(a, c)) {
    34         ans++;
    35     } 
    36     for (int i = 1; i <= 9; i++) {
    37         if (!st[i]) {
    38             st[i] = true;
    39             dfs_c(u + 1, a, c * 10 + i);
    40             st[i] = false;
    41         }
    42     }
    43 } 
    44 void dfs_a(int u, int a) { //参数一:u表示已经用了多少个数字, 参数二:表示a的值 
    45     if (a >= n) { //a,b,c三个数字至少有一位 
    46         return;
    47     }
    48     //对于a<n的每种方案,枚举c 
    49     if (a) {
    50         dfs_c(u, a, 0); //u个数了,a的值为a,c的值为0 
    51     }
    52     //枚举当前这一位可以用哪个数字
    53     for (int i = 1; i <= 9; i++) {
    54         if (!st[i]) {
    55             st[i] = true;
    56             dfs_a(u + 1, a * 10 + i);
    57             st[i] = false; //回溯恢复现场 
    58         }
    59     } 
    60 }
    61 int main() {
    62     cin >> n;
    63     dfs_a(0, 0); //一个数都没有, a = 0 
    64     cout << ans << endl; 
    65     return 0;
    66 }
  • 相关阅读:
    bzoj 1031: [JSOI2007]字符加密Cipher
    [BZOJ5011][JXOI2017]颜色
    [BZOJ4765]普通计算姬(分块+树状数组)
    [BZOJ3261]最大异或和(可持久化Trie)
    [BZOJ4861][BJOI2017]魔法咒语(AC自动机+矩阵优化DP)
    [BZOJ2286][SDOI2011]消耗战(虚树DP)
    [BZOJ2109][NOI2010]航空管制(贪心+拓扑)
    [BZOJ1305][CQOI2009]跳舞(网络流)
    [Nescafé41]编码病毒(循环卷积)
    [Nescafé41]异化多肽(多项式求逆元)
  • 原文地址:https://www.cnblogs.com/fx1998/p/12767163.html
Copyright © 2011-2022 走看看