几道深搜题

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

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

深度优先搜索(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;
}
原文地址:https://www.cnblogs.com/loceaner/p/13647843.html