zoukankan      html  css  js  c++  java
  • [刷题] 搜索剪枝技巧

    https://wenku.baidu.com/view/83b35f22aaea998fcc220e6a.html


    深度优先搜索问题的优化技巧
    提及:

    ZOJ1937

    IOI2000 BLOCK

    NOI2005 智慧珠

    USACO weight

    提交通道:weight

    Description

    已知原数列(a_1,a_2,dots,a_n)中的前(1)项,前(2)项,前(3)项,(dots),前(n)项的和,以及后(1)项,后(2)项,后(3)项,(dots),后(n)项的和,但是所有的数都被打乱了顺序。
    此外,我们还知道数列中的数存在于集合(S)中。试求原数列。
    当存在多组可能的数列时,求字典序最小的数列。
    数据范围 (1le nle1000,1le mle500) ,且 (S in{1,2,dots,500})

    Solution

    详情见文章和代码。

    Code

    // Author: wlzhouzhuan
    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #include <bits/stdc++.h>
    using namespace std;
     
    #define ll long long
    #define ull unsigned long long
    #define rint register int
    #define rep(i, l, r) for (rint i = l; i <= r; i++)
    #define per(i, l, r) for (rint i = l; i >= r; i--)
    #define mset(s, _) memset(s, _, sizeof(s))
    #define pb push_back
    #define pii pair <int, int>
    #define mp(a, b) make_pair(a, b)
     
    inline int read() {
      int x = 0, neg = 1; char op = getchar();
      while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
      while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
      return neg * x;
    }
    inline void print(int x) {
      if (x < 0) { putchar('-'); x = -x; }
      if (x >= 10) print(x / 10);
      putchar(x % 10 + '0');
    }
    
    const int N = 20000005;
    int can[N], s[N], n, m;
    
    int a[N], b[N], lsum[N], rsum[N];
    void dfs(int k, int i, int j) { // 到s[k],已经确定a[1],a[2]...a[i]和a[j],a[j+1]....a[n] 
      if (i + 1 == j) {
        for (int p = i; p >= 1; p--) b[p] = a[p] - a[p - 1];
        for (int p = j; p <= n; p++) b[p] = a[p] - a[p + 1];
        for (int p = 1; p <= n; p++) lsum[p] = lsum[p - 1] + b[p];
        for (int p = n; p >= 1; p--) rsum[p] = rsum[p + 1] + b[p];
        /*printf("preout = 
    ");
        for (int p = 1; p <= n; p++) {
          printf("%d ", b[p]);
        } 
        puts("");
        */
        int le = n, ri = 1, tp = 2 * n;
        while (tp > n) {
          if (le > i && lsum[le] == s[tp]) le--;
          else if (ri < j && rsum[ri] == s[tp]) ri++;
          else return ;
          tp--;
        }
        for (int p = 1; p <= n; p++) {
          printf("%d ", b[p]);
        } 
        puts("");
        exit(0);
      }
      if (k >= n + 1) {
        return ;
      }
      if (s[k] - a[i] > 0 && s[k] - a[i] <= 500 && can[s[k] - a[i]]) {
        a[i + 1] = s[k];
        dfs(k + 1, i + 1, j);
        a[i + 1] = 0;
      }
      if (s[k] - a[j] > 0 && s[k] - a[j] <= 500 && can[s[k] - a[j]]) {
        a[j - 1] = s[k];
        dfs(k + 1, i, j - 1);
        a[j - 1] = 0;
      }
    }
    
    int main() {
      n = read();
      for (int i = 1; i <= 2 * n; i++) s[i] = read();
      sort(s + 1, s + 2 * n + 1);
      m = read();
      while (m--) {
        int x = read();
        can[x] = 1;
      }  
      dfs(1, 0, n + 1);
      return 0; 
    }
    
  • 相关阅读:
    Android 屏幕适配比例
    不错的网站
    Android十大常用技术揭秘-挑战
    Linux 自己的常用命令
    Android 常用配置
    Android 边框 给控件添加边框
    Linux 常用命令大全
    TCP/IP、Http、Socket的区别
    Android 之基于 HTTP 协议的通信详解
    JavaScript基础:(加号,数值转换,布尔转换)
  • 原文地址:https://www.cnblogs.com/wlzhouzhuan/p/12748195.html
Copyright © 2011-2022 走看看