zoukankan      html  css  js  c++  java
  • 几道深搜题

    写这篇文章的目的是复习一下搜索,以至于不会的题也不至于爆零。

    可能并不会有什么解析,因为搜索大多都是瞎搞。

    深度优先搜索(DFS),即按照深度优先的顺序搜索的算法,通常用递归的方式实现。

    P1219 [USACO1.5]八皇后 Checker Challenge

    link

    一年半之前做的,现在全忘了。

    不会对角线,以为只有两条。

    关于对角线的编号,可以看这里

    里面出了一个错误那就是左斜右斜的对角线个数都是 (2 imes n-1) 而不是 (2 imes n+1)

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int A = 400;
    const int B = 1e6 + 11;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
      char c = getchar();
      int x = 0, f = 1;
      for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
      for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
      return x * f;
    }
    
    int n, ans, a[A], line[A], row[A], diagleft[A], diagright[A];
    
    void dfs(int cnt) {
      if (cnt == n + 1) {
        ans++;
        if (ans <= 3) {
          for (int i = 1; i <= n; i++) cout << a[i] << " ";
          puts("");
        }
        return;
      }
      int i = cnt;
      for (int j = 1; j <= n; j++) {
        if (!row[j] && !diagleft[i - j + n] && !diagright[i + j - 1]) {
          row[j] = 1, diagleft[i - j + n] = 1, diagright[i + j - 1] = 1;
          a[cnt] = j;
          dfs(cnt + 1);
          row[j] = 0, diagleft[i - j + n] = 0, diagright[i + j - 1] = 0;
        }
      }
    }
    
    int main() {
      n = read();
      dfs(1);
      cout << ans << '
    ';
      return 0;
    }
    

    P1019 单词接龙

    link

    一年半前写的,现在也全忘了,真的是不会做了/kb

    直接预处理出能够拼接的串之间能获得的价值,然后搜索就好了。

    注意:

    1. 自己和自己也是可以拼接的,比如 (ababab)
    2. 如果两个串多个位置能够匹配,就选重叠部分最小的,比如 (abababababab),和 (ababababab),应该取最后一个 (ab) 进行匹配,这样才能保证答案最大。
    #include <cmath>
    #include <cstdio>
    #include <string>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int A = 301;
    const int B = 1e6 + 11;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
      char c = getchar();
      int x = 0, f = 1;
      for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
      for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
      return x * f;
    }
    
    char s[30][A], fir;
    int n, ge[30][30], ans, vis[30];
    
    void dfs(int now, int sum) {
      ans = max(ans, sum);
      for (int i = 1; i <= n; i++) {
        if (ge[now][i]) {
          if (vis[i] < 2) {
            vis[i]++;
            dfs(i, sum + ge[now][i]);
            vis[i]--;
          }
        }
      }
    }
    
    int main() {
      n = read();
      for (int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
      cin >> fir;
      for (int i = 1; i <= n; i++) {
        int len1 = strlen(s[i] + 1), len2, flag = 0;
        for (int j = 1; j <= n; j++) {
          len2 = strlen(s[j] + 1);
          for (int k = len1; k >= 2; k--) {
            if (s[i][k] == s[j][1]) {
              int pos1 = k, pos2 = 1;
              while (s[i][pos1 + 1] == s[j][pos2 + 1] && pos1 + 1 <= len1 && pos2 + 1 <= len2) pos1++, pos2++; 
              if (pos1 == len1 && pos2 != len2) ge[i][j] = len2 - pos2, flag = 1;
              if (flag) break; 
            }
          }
        }
      }
      for (int i = 1; i <= n; i++) {
        if (s[i][1] == fir) memset(vis, 0, sizeof(vis)), vis[i]++, dfs(i, strlen(s[i] + 1));
      }
      cout << ans << '
    ';
      return 0;
    }
    

    P5194 [USACO05DEC]Scales S

    咋看都不像是个深搜,但是由于每个砝码的质量至少等于前面两个砝码的质量的和,所以真正能够满足 (a_ile2^{30}) 的数不超过 (45) 个,题目没有给出 (a_i) 范围的原因也就在这里,所以可以直接用搜索解决。

    剪枝:

    1. 前缀和优化
    2. 从大的往小的拿
    3. 当前答案大于 (c) 直接跳出
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define int long long
    using namespace std;
    
    const int A = 1e5 + 11;
    const int B = 1e6 + 11;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
      char c = getchar();
      int x = 0, f = 1;
      for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
      for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
      return x * f;
    }
    
    int n, c, ans, a[A], vis[A], s[A];
    
    void dfs(int sum, int last) {
      if (sum > c) return;
      ans = max(ans, sum);
      if (sum + s[last - 1] <= c) {
        ans = max(ans, sum + s[last - 1]);
        return;
      }
      for (int i = 1; i < last; i++) {
        if (!vis[i]) {
          vis[i] = 1;
          dfs(sum + a[i], i);
          vis[i] = 0;
        }
      }
    }
    
    signed main() {
      n = read(), c = read();
      int cnt;
      for (int i = 1; i <= n; i++) {
        a[i] = read();
        s[i] = s[i - 1] + a[i];
        if (a[i] > c) cnt = i;
      }
      n = (cnt == 0) ? n : cnt;
      dfs(0, n + 1);
      cout << ans << '
    ';
      return 0;
    }
    

    P5440 【XR-2】奇迹

    link

    真的是很暴力了,直接枚举字符串年月日即可。

    注意:

    1. 多测不清空,爆零两行泪
    2. (8) 的时候跑步过去,本地跑出来再交。
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int A = 1e5 + 11;
    const int B = 1e6 + 11;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
      char c = getchar();
      int x = 0, f = 1;
      for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
      for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
      return x * f;
    }
    
    int day[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    int ans;
    char s[9];
    
    //判断质数 
    inline bool is_prime(int x) {
      if (x == 0 || x == 1) return 0;
      if (x == 2) return 1;
      if (!(x & 1)) return 0;
      for (int i = 2; i * i <= x; i++) {
        if (x % i == 0) return 0;
      }
      return 1;
    }
    
    //判断闰年
    inline bool is_rn(int x) {
      return (x % 4 == 0 && x % 100 != 0) || x % 400 == 0;
    } 
    
    //dfs
    void dfs(int cnt) {
      if (cnt == 6) {
        int now = 0;
        for (int i = 7; i <= 8; i++)
          now = now * 10 + (s[i] ^ 48);
        if (!is_prime(now)) return; 
      }
      else if (cnt == 4) {
        int now = 0;
        for (int i = 5; i <= 8; i++)
          now = now * 10 + (s[i] ^ 48);
        if (!is_prime(now)) return;
      }
      else if (cnt == 0) {
        int now = 0;
        for (int i = 1; i <= 4; i++)
          now = now * 10 + (s[i] ^ 48);
        if (!now) return;
        if (is_rn(now)) day[2] = 29;
        now = 0;
        for (int i = 5; i <= 6; i++) 
          now = now * 10 + (s[i] ^ 48);
        if (!now || now > 12) return;
        int d = day[now];
        day[2] = 28;
        now = 0;
        for (int i = 7; i <= 8; i++) 
          now = now * 10 + (s[i] ^ 48);
        if (!now || now > d) return;
        now = 0;
        for (int i = 1; i <= 8; i++) 
          now = now * 10 + (s[i] ^ 48);
        if (is_prime(now)) { ans++; return; }
      }
      if (s[cnt] == '-') {
        if (cnt == 1 || cnt == 2 || cnt == 3 || cnt == 4 || cnt == 6 || cnt == 8) {
          for (int i = 0; i <= 9; i++) {
            s[cnt] = i + '0';
            dfs(cnt - 1);
            s[cnt] = '-';
          }
        }
        else if (cnt == 5) {
          for (int i = 0; i <= 1; i++) {
            s[cnt] = i + '0';
            dfs(cnt - 1);
            s[cnt] = '-';
          }
        }
        else if (cnt == 7) {
          for (int i = 0; i <= 3; i++) {
            s[cnt] = i + '0';
            dfs(cnt - 1);
            s[cnt] = '-';
          }
        }
      }
      else dfs(cnt - 1);
    }
    
    int main() {
      int T = read();
      while (T--) {
        ans = 0;
        scanf(" %s", s + 1);
        int flag = 0;
        for (int i = 1; i <= 8; i++) {
          if (s[i] != '-') flag = 1;
        }
        if (flag) dfs(8);
        else {
          cout << "55157
    ";
          continue;
        }
        cout << ans << '
    ';
      }
    }
    

    P1378 油滴扩展

    link

    写不动啦,饶了我吧!

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int A = 10;
    const int B = 1e6 + 11;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    const double Pi = 3.14159265358979323846;
    
    inline int read() {
    	char c = getchar();
    	int x = 0, f = 1;
    	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
    	return x * f;
    }
    
    int n, m, vis[A];
    double x1, x2, _y, y2, x[A], y[A], l, r, u, d;
    double dis[A][A], ri[A], ans;
    
    void dfs(int now, double s) {
      if (now == n + 1) ans = max(ans, s);
      for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
          ri[i] = min(min(x[i] - l, r - x[i]), min((y[i] - u), (d - y[i])));
          for (int j = 1; j <= n; j++) if(vis[j]) ri[i] = min(ri[i], dis[i][j] - ri[j]);
          vis[i] = 1;
          if (ri[i] < 0) ri[i] = 0;
          dfs(now + 1, s + ri[i] * ri[i] * Pi);
          vis[i] = 0;
        }
      }
    }
    
    int main() {
      n = read();
      scanf("%lf%lf%lf%lf", &x1, &_y, &x2, &y2);
      for (int i = 1; i <= n; i++) scanf("%lf%lf", &x[i], &y[i]);
      l = min(x1, x2), r = max(x1, x2), u = min(_y, y2), d = max(_y, y2);
      for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
          dis[i][j] = sqrt((double)(x[i] - x[j]) * (x[i] - x[j]) + (double)(y[j] - y[i]) * (y[j] - y[i]));
      dfs(1, 0.0);
      printf("%.0lf", double(r - l) * double(d - u) - ans);
      return 0;
    }
    
  • 相关阅读:
    [考试反思]0511省选模拟93:平衡
    [考试反思]0509省选模拟92:警示
    [考试反思]0508省选模拟91:小雨
    [考试反思]0507省选模拟90:信任
    [考试反思]0506省选模拟89:无事
    [专题总结]2-sat及题目&题解(3/5 complete)
    [考试反思]0505省选模拟88:滑稽
    [考试反思]0504省选模拟87:开花
    [考试反思]0502省选模拟86:恐惧
    [考试反思]0501省选模拟85:低落
  • 原文地址:https://www.cnblogs.com/loceaner/p/13647843.html
Copyright © 2011-2022 走看看