几道深搜题
写这篇文章的目的是复习一下搜索,以至于不会的题也不至于爆零。
可能并不会有什么解析,因为搜索大多都是瞎搞。
深度优先搜索(DFS),即按照深度优先的顺序搜索的算法,通常用递归的方式实现。
P1219 [USACO1.5]八皇后 Checker Challenge
一年半之前做的,现在全忘了。
不会对角线,以为只有两条。
关于对角线的编号,可以看这里
里面出了一个错误那就是左斜右斜的对角线个数都是 \(2\times n-1\) 而不是 \(2\times 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 << '\n';
return 0;
}
P1019 单词接龙
一年半前写的,现在也全忘了,真的是不会做了/kb
直接预处理出能够拼接的串之间能获得的价值,然后搜索就好了。
注意:
- 自己和自己也是可以拼接的,比如 \(ababab\)。
- 如果两个串多个位置能够匹配,就选重叠部分最小的,比如 \(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 << '\n';
return 0;
}
P5194 [USACO05DEC]Scales S
咋看都不像是个深搜,但是由于每个砝码的质量至少等于前面两个砝码的质量的和,所以真正能够满足 \(a_i\le2^{30}\) 的数不超过 \(45\) 个,题目没有给出 \(a_i\) 范围的原因也就在这里,所以可以直接用搜索解决。
剪枝:
- 前缀和优化
- 从大的往小的拿
- 当前答案大于 \(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 << '\n';
return 0;
}
P5440 【XR-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\n";
continue;
}
cout << ans << '\n';
}
}
P1378 油滴扩展
写不动啦,饶了我吧!
#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;
}
转载不必联系作者,但请声明出处