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做法还比较短小。
- 首先得知道异或的性质 x = x ^ y ^ y
- 用dis[u]代表u到根节点的路径异或,dis[v]代表v到根节点的路径异或,依次,我们要求的就是dis[u]^dis[v]的值。
- 接下来就是如何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;
}