一些经典搜索题目集

POJ1979 Red and Black

题意:简单的搜索,经典连通块问题。

做法:深搜广搜都可,下面是简短的深搜代码,POJ交题不能用万能头文件呀呀呀。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
typedef long long ll;
typedef pair<ll, int> pli;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
template<class T>
void read(T &res) {
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
const int N = 24;
int ne[4][2] = {1, 0, -1, 0, 0, -1, 0, 1};
int n, m, res;
int vis[N][N];
char mp[N][N];
void dfs(int x, int y) {
  res++;
  for(int i = 0; i < 4; ++i) {
    int tx = x + ne[i][0];
    int ty = y + ne[i][1];
    if(tx < 1 || ty < 1 || tx > m || ty > n || mp[tx][ty] != '.' || vis[tx][ty])
      continue;
    vis[tx][ty] = 1;
    dfs(tx, ty);
  }
}
int main() {
  while(scanf("%d%d", &n, &m), n && m) {
    res = 0;
    memset(vis, 0, sizeof vis);
    for(int i = 1; i <= m; ++i) {
      scanf("%s", mp[i] + 1);
    }
    for(int i = 1; i <= m; ++i) {
      for(int j = 1; j <= n; ++j) {
        if(mp[i][j] == '@') { dfs(i, j); break; }
      }
    }
    printf("%d\n", res);
  }
  return 0;
}

P1443 马的遍历

题意:有一个n*m的棋盘(1<n,m<=400),在某个点上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步。

做法:敲简单,8个方向上广搜,手痒写了一发Java,有一个点T了…洛谷还是对Java不太友好啊,下面C++代码。

代码:

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
typedef long long ll;
typedef pair<ll, int> pli;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
template<class T>
void read(T &res) {
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
const int N = 405;
int ne[8][2] = { {1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, 1}, {-2, -1} };
int vis[N][N], mp[N][N];
struct xx {
  int x, y, step;
};
void bfs(int n, int m, int x, int y) {
  queue<xx> q;
  while(!q.empty()) q.pop();
  q.push(xx{x, y, 0});
  mp[x][y] = 0; vis[x][y] = 1;
  int tx, ty;
  while(!q.empty()) {
    xx cur = q.front(); q.pop();
    for(int i = 0; i < 8; ++i) {
      tx = cur.x + ne[i][0];
      ty = cur.y + ne[i][1];
      if(tx <= 0 || ty <= 0 || tx > n || ty > m || vis[tx][ty] != 0) continue;
      mp[tx][ty] = cur.step + 1; vis[tx][ty] = 1;
      q.push(xx{tx, ty, cur.step+1});
    }
  }
}
int main() {
  int n, m, x, y;
  read(n); read(m); read(x); read(y);
  for(int i = 1; i <= n; ++i)
    for(int j = 1; j <= m; ++j)
      mp[i][j] = -1;
  bfs(n, m, x, y);
  for(int i = 1; i <= n; ++i) {
    for(int j = 1; j <= m; ++j)
      printf("%-5d", mp[i][j]);
    printf("\n");
  }
  return 0;
}

P1135 奇怪的电梯

题意:经典老题了,每个楼层都有按键k,可以选择上k楼,也可以选择下k楼,问最少按多少次键能够从a楼到b楼。

做法:敲简单,2个方向上广搜。

代码:

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
typedef long long ll;
typedef pair<ll, int> pli;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
template<class T>
void read(T &res) {
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
int lou[203], vis[203];
int n, a, b;
int bfs() {
  queue<pii> q;
  while(!q.empty()) q.pop();
  q.push(pii{a, 0});
  vis[a] = 1;
  int mid;
  while(!q.empty()) {
    pii cur = q.front(); q.pop();
    if(cur.first == b) return cur.second;
    mid = cur.first + lou[cur.first];
    if(mid <= n && !vis[mid])
      q.push(pii{ mid, cur.second + 1 }), vis[mid] = 1;
    mid = cur.first - lou[cur.first];
    if(mid > 0 && !vis[mid])
      q.push(pii{ mid, cur.second + 1 }), vis[mid] = 1;
  }
  return -1;
}
int main() {
  read(n); read(a); read(b);
  for(int i = 1; i <= n; ++i) read(lou[i]);
  cout << bfs() << endl;
  return 0;
}

P1036 选数

题意:给出n个数字,要求向其中选k个数字,使他们加起来的和是一个素数。

做法:组合数爆搜,每个位置应当在选过位置之后,不然会有重复。

代码:

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
typedef long long ll;
typedef pair<ll, int> pli;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
template<class T>
void read(T &res) {
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
int k, n, res, a[22], vis[22];
inline bool isprime(int x) {
  if(x == 1) return false;
  if(x == 2 || x == 3) return true;
  if(x%6 != 1 && x%6 != 5) return false;
  for(int i = 5; i*i <= x; ++i) {
    if(x%i == 0 || x%(i+2) == 0) return false;
  }
  return true;
}
void dfs(int pos, int step, int sum) {  //pos是为了避免重复
  if(pos > n) return ;
  if(step == k) {
    if(isprime(sum)) res++;
    return ;
  }
  for(int i = pos; i <= n; ++i) {
    if(!vis[i]) {
      vis[i] = 1;
      dfs(i, step + 1, sum + a[i]);
      vis[i] = 0;
    }
  }
}
int main() {
  read(n); read(k);
  for(int i = 1; i <= n; ++i) read(a[i]);
  dfs(1, 0, 0);
  printf("%d\n", res);
  return 0;
}

HDU1455 Sticks

题意:若干长度不一样的木棒,将其拼成若干长度相等的木棒,求长度最小是多少。

做法:可选棍子的长度应该在最长木棒与所有木棒长度之和之间,所以依次进行搜索即可。

代码:

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
typedef long long ll;
template<class T>
void read(T &res) {
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
const int N = 70;
int n, sum, len, num, a[N], vis[N];
// n - n根棍子,sum - n根棍子的总长,len - 每根棍子的长度
//num - 一共有多少根len长度的棍子,a数组记录切割后棍子的长度,vis用于搜索
bool cmp(int x, int y) { return x > y; }
int dfs(int mid_num, int mid_len, int pos) {
  if(mid_num == num) return 1;  //如果棍子数量对上了
  if(mid_len == len) return dfs(mid_num+1, 0, 1); 
  //如果长度够了,再拼接下一根棍子
  for(int i = pos; i <= n; ++i) {
    if(!vis[i] && mid_len + a[i] <= len) {
      vis[i] = 1;
      if(dfs(mid_num, mid_len + a[i], i + 1)) return 1;
      vis[i] = 0;
      if(mid_len == 0) return 0;
      while(i + 1 <= n && a[i+1] == a[i]) i++;
    }
  }
  return 0;
}
int main() {
  while(scanf("%d", &n), n) {
    sum = 0;
    for(int i = 1; i <= n; ++i) {
      read(a[i]); sum += a[i];
    }
    sort(a+1, a+n+1, cmp); //从大至小排序,方便搜索
    int res = -1;
    for(int i = a[1]; i <= sum; ++i) {
      if(sum % i == 0) {
        memset(vis, 0, sizeof vis);
        len = i; num = sum / len;
        if(dfs(0, 0, 1)) { res = len; break; }
      }
    }
    printf("%d\n", res);
  }
  return 0;
}

POJ2488 A Knight’s Journey

题意:以马的行走规则遍历整个棋盘,输出路径。若情况有多种,输出字典序最小的一种;若没有满足条件的,则输出"impossible"。

做法:直接上dfs,一旦有满足情况的就置标记flag为1,用一个vector来维护,具体看代码。

代码:

#include<iostream>
#include<vector>
#include<cstring>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
typedef long long ll;
typedef pair<ll, int> pli;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
template<class T>
void read(T &res) {
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
const int N = 10;
int ne[8][2] = { {-2, -1}, {-2, 1}, {-1, -2}, {-1, 2}, {1, -2}, {1, 2}, {2, -1}, {2, 1} };
int mp[N][N], vis[N][N], n, m, flag;
vector<pii> res;
void dfs(int x, int y, int step) {
  if(step >= n * m) {
    if(!flag) {  //一旦满足就输出并置标记flag为1
      flag = 1;
      int len = res.size();
      for(int i = 0; i < len; ++i) {
        printf("%c%d", res[i].first - 1 + 'A', res[i].second);
      }
    }
    return ;
  }
  int tx, ty;
  for(int i = 0; i < 8; ++i) {
    tx = x + ne[i][0];
    ty = y + ne[i][1];
    if(tx > 0 && ty > 0 && tx <= n && ty <= m && !vis[tx][ty]) {
      vis[tx][ty] = 1;
      res.push_back(make_pair(tx, ty));
      dfs(tx, ty, step+1);
      res.pop_back(); vis[tx][ty] = 0;
    }
  }
}
int main() {
  int t; read(t);
  for(int i = 1; i <= t; ++i) {
    memset(vis, 0, sizeof vis);
    res.clear(); flag = 0;
    printf("Scenario #%d:\n", i);
    read(m); read(n);
    vis[1][1] = 1;
    res.push_back(make_pair(1, 1));
    dfs(1, 1, 1);
    if(!flag) printf("impossible");
    printf("\n\n");
  }
  return 0;
}

P2420 让我们异或吧

题意:给出一些无向边的权值,每次询问u, v两点间路径的异或值。

做法:看到dalao们说用lca,树链剖分,吓得我赶紧退出游戏,看到一个dfs做法还比较短小。

  1. 首先得知道异或的性质 x = x ^ y ^ y
  2. 用dis[u]代表u到根节点的路径异或,dis[v]代表v到根节点的路径异或,依次,我们要求的就是dis[u]^dis[v]的值。
  3. 接下来就是如何dfs了。

代码:

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
typedef long long ll;
typedef pair<ll, int> pli;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
template<class T>
void read(T &res) {
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
const int N = 1e5+5;
vector<pii> edge[N];  //first - v, second - w
int n, dis[N];
inline void dfs(int now, int f, int val) {  //妙啊妙啊
  dis[now] = val;
  int len = edge[now].size();
  for(int i = 0; i < len; ++i) {
    if(edge[now][i].first != f) {
      dfs(edge[now][i].first, now, val^edge[now][i].second);
    }
  }
}
int main() {
  int u, v, w;
  read(n);
  for(int i = 1; i < n; ++i) {
    read(u); read(v); read(w);
    edge[u].push_back(make_pair(v, w));
    edge[v].push_back(make_pair(u, w));
  }
  dfs(1, 1, 1);
  int m; read(m);
  while(m--) {
    read(u); read(v);
    printf("%d\n", dis[u]^dis[v]);
  }
  return 0;
}
发布了28 篇原创文章 · 获赞 14 · 访问量 2969

猜你喜欢

转载自blog.csdn.net/qq_43408978/article/details/102809276