[kuangbin带你飞]专题一 简单搜索 题解
A - 棋盘问题 POJ 1321
一个不规则的棋盘,‘#’区域才可以摆放旗子,且同行同列只能有一个棋子。输出k个棋子的所有摆放方案。
思路:
遍历每一行每一列,放棋子加标记dfs即可。
int n,k,ans;
string s[10];
bool column[10];
void dfs(int r,int k){//k 当前剩余棋子数
if(k == 0){
++ans;
return;
}
if(r == n) return;
dfs(r + 1,k);
for(int j = 0; j < n; j++){
if(s[r][j] == '#' && !column[j]){
column[j] = true;
dfs(r + 1, k - 1);
column[j] = false;//不放
}
}
}
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);
while(cin >> n >> k){
if(n == -1 && k == -1) break;
for(int i = 0; i < 8; i++) column[i] = false;
ans = 0;
memset(column,false,sizeof column);
for(int i = 0; i < n; i++) cin >> s[i];
dfs(0,k);
cout << ans << endl;
}
return 0;
}
B - Dungeon Master POJ 2251
给你一个3维的迷宫,'#'为岩石不能通过,'.'可以通过。起点'S',终点'E'。每走一步耗时为1,询问到达重点的最短时间。直接bfs即可,字符数组g(z,x,y):第z层,x行,y列。在每一个位置可以前后左右上下移动。
string s[35][35];
bool flag,vis[31][31][31];
struct node{
int z,x,y,time;
}cur,top;
int a,b,c,sx,sy,sz,dir[6][3] = {1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1};
bool check(node cur){
if(vis[cur.z][cur.x][cur.y]) return false;
if(cur.z < 0 || cur.x < 0 || cur.y < 0 || cur.z >= c || cur.x >= a || cur.y >= b) return false;
return true;
}
void bfs(){
cur.z = sz,cur.x = sx,cur.y = sy,cur.time = 0;
queue<node> q;
q.push(cur);
while(!q.empty()){
top = q.front();
q.pop();
cur.time = top.time + 1;
for(int i = 0; i < 6; i++){
cur.z = top.z + dir[i][0];
cur.x = top.x + dir[i][1];
cur.y = top.y + dir[i][2];
if(check(cur) && s[cur.z][cur.x][cur.y] != '#'){
if(s[cur.z][cur.x][cur.y] == 'E'){
cout << "Escaped in " << cur.time << " minute(s)." << endl;
return;
}
vis[cur.z][cur.x][cur.y] = true;
q.push(cur);
}
}
}
cout << "Trapped!" << endl;
}
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
while(cin >> c >> a >> b && (a + b + c)){
flag = true;
memset(vis,false,sizeof vis);
for(int i = 0; i < c; i++){
for(int j = 0; j < a; j++){
cin >> s[i][j];
for(int k = 0; k < b; k++){
if(s[i][j][k] == 'S') sz = i,sx = j,sy = k;
}
}
}
bfs();
}
return 0;
}
C - Catch That Cow POJ 3278
John初始位于n位置,牛位于k位置。牛的位置不变,john有两种移动方式:
- 移动到相邻位置 x + 1 or - 1
- 移动到2 * x位置
找到牛需要的最少移动次数?若牛的位置在人之前,则answer = n - k。其他情况,直接bfs,到达每一个节点,先判断节点是否在[0,100000]中,再判断是否到达过。
- DP做法:
- dp(i)表示n移动到n~k间第i个位置所需的最小移动次数
- dp(i) = abs(i - n),(n >= k,不需要计算)
- dp[i] 可以通过dp[i - 1],dp[i + 1]得到
- 第二种移动为2 * i,i 奇偶分开讨论
- i is odd:dp[i] = min(min(dp[i],dp[i - 1] + 1),min(dp[i - 1 >> 1] + 2,dp[i + 1 >> 1] + 2))
- i is even:dp[i] = min(min(dp[i],dp[i -1] + 1),min(dp[i >> 1] + 1,dp[i >> 1 + 1] + 2))
int DP(){
for(int i = 0; i <= k; i++) dp[i] = abs(n - i);//n点一步步移动到i
for(int i = n + 1; i <= k; i++){
dp[i] = min(dp[i],dp[i - 1] + 1);
if(i & 1){
dp[i] = min(dp[i],dp[i / 2] + 2);
dp[i] = min(dp[i],dp[i / 2 + 1] + 2);
}else{
dp[i] = min(dp[i],dp[i / 2] + 1);
dp[i] = min(dp[i],dp[i / 2 + 1] + 2);
}
}
return dp[k];
}
D - Fliptile
类似于关灯游戏,对第一行的每一个点,都有关 or 开两种选择,首先枚举第一行的各个状态,之后搜索其他行:上一行中开灯位置下一行必须翻转 -- 所有行翻转完毕后,判断最后一行是否全零。字典序最小,左上-- 右下枚举,靠近右下最优。
const int kN = 17,inf = 0x3f3f3f3f;
int n,m,res,g[kN][kN],book[kN][kN],mid[kN][kN],ans[kN][kN],dir[2][5] = {1,-1,0,0,0,0,0,1,-1,0};
//g数组,记录当前的各点状态,book,存储各点初始状态。
//mid数组,记录当前各点翻转情况,ans数组,存储当前最优翻转情况
bool check(int x,int y){
if(x < 0 || y < 0 || x >= n || y >= m) return false;
return true;
}
void turn(int x,int y){
for(int i = 0; i < 5; i++){
int tx = x + dir[0][i];
int ty = y + dir[1][i];
if(check(tx,ty)) g[tx][ty] ^= 1;
}
}
void dfs_b(int r,int sum){//其它行
if(r == n){//所有行已翻转完毕
for(int i = 0; i < m; i++){
if(g[r - 1][i]) return;
}
if(sum <= res){
res = sum;
memcpy(ans,mid,sizeof mid);
}
return;
}else{
for(int i = 0; i < m; i++){
if(g[r - 1][i]){//上一行决定翻转位置
++sum;
mid[r][i] = 1;
turn(r,i);
}else mid[r][i] = 0;
}
dfs_b(r + 1,sum);//下一行
}
}
void dfs_a(int l,int sum){//列 翻转个数
if(l == m){
for(int i = 0; i < m; i++)
if(mid[0][i]) turn(0,i);
dfs_b(1,sum);//其他行
memcpy(g,book,sizeof book);//恢复g数组
return;
}else{
mid[0][l] = 1;//turn
dfs_a(l + 1,sum + 1);
mid[0][l] = 0;//unturn
dfs_a(l + 1,sum);
}
}
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++) cin >> book[i][j];
}
res = inf;
memcpy(g,book,sizeof book);
dfs_a(0,0);
if(res == inf) cout << "IMPOSSIBLE" << endl;
else{
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(j) cout << ' ';
cout << ans[i][j];
}
cout << endl;
}
}
return 0;
}
E - Find The Multiple
输入一个n,输出由0,1组成的m为n的倍数,直接遍历所有可能...
long long bfs(){
queue<long long> q;
q.push(1);
while(!q.empty()){
long long t = q.front();
q.pop();
if(!(t % n)) return t;
q.push(t * 10);
q.push(t * 10 + 1);
}
}
F - Prime Path
找到任意两素数a,b间的最便宜的素数路径:a -->b,每次只能够变换某一位上的数字,且变换的数字也是素数,求最小变换次数。
- 先使用素数筛求出所有的四位素数
- bfs,模拟修改。
int t,a,b;
bool prime[10005],vis[10005];
struct node{
int x,t;
}top;
void init(){//将10000以内的素数标记出来 false 表示是素数
prime[1] = true;
for(int i = 2; i <= 10000; i++){
if(!prime[i]){
for(int j = 2 * i; j <= 10000; j += i) prime[j] = true;
}
}
}
void bfs(){
queue<node> q;
q.push({a,0});
vis[a] = true;
while(!q.empty()){
top = q.front();
q.pop();
if(top.x == b){
cout << top.t << endl;
return;
}
for(int i = 0; i < 4; i++){
for(int j = 0; j < 10; j++){
if(i == 3 && !j) continue;//最高位不可为0
int t = top.x - (top.x / int(pow(10,i)) % 10) * pow(10,i) + j * pow(10,i);
if(!prime[t] && !vis[t]){
vis[t] = true;
q.push({t,top.t + 1});
}
}
}
}
cout << "Impossible" << endl;
}
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> t;
init();
while(t--){
memset(vis,false,sizseof(vis));
cin >> a >> b;
bfs();
}
return 0;
}
G - Shuffle'm Up
两个字符串s1,s2,均含有c个字符。s1,s2交叉组成s12,s12尾部的c个字符为s1,其它为s2,循环操作。输入s1,s2,最终状态s12。询问结果多少次操作可以得到s12。。。
- 模拟......,记录每次模拟的s12,注意不要重复操作
H - Pots
两个瓶子,量出 c L水需要的最少操作数。
操作:
1. fill(i),倒满i
2. drop(i),全部倒掉i中的水
3. pour(i,j),将i中的水倒入j中
思路:
1.两个杯子之间互倒(两种)
2.每个杯子可以倒满后者全部倒掉
3.由于需要输出最终操作步骤,在结构体中增加一个数组存储每次的操作
4.跑一边bfs...
//代码大致思路同M - 非常可乐
node.turn = top.turn+1;
if(top.a < a){//fill
node.a = a,node.b = top.b;
if(!vis[node.a][node.b]){
node.ans = top.ans;
node.ans.push_back("FILL(1)");
q.push(node);
vis[node.a][node.b] = true;
}
}
I - Fire Game
输入n*m的矩阵,'#'表示草地,可燃烧。'.'表示空地,不可燃烧.询问点燃哪两块草地,可以是所有的草地最快燃烧。
- 对任意一块草地,bfs,记录到达各点的时间,记录最后一层燃烧的任意一个草地x
- 若bfs结束后存在未燃烧草地,则直接计算未燃烧草地燃烧用时
- x bfs,记录时间,当到达某点时用时更小则修改这个点,维护一个最大时间。
J - Fire!
J点位人所在初始位置,F点位各个着火点,每个着火点bfs,记录其他可燃烧点的最快燃烧时间,最后j点bfs,判断是否存在到达边界时未燃烧的点。
K - 迷宫问题
定义一个5X5的二维数组:它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
要求输出左上角到右下角的最短路径。
- bfs并记录每一步的上一个位置(模拟链表思想),最后通过栈输出路径...
//bfs模板题 记录各自父节点 找到答案 父节点入栈 --> 输出
int g[6][6],dir[2][4] = {-1,1,0,0,0,0,-1,1};
bool vis[6][6];
struct node{
int x,y;
}cur,top,record[6][6];
bool judge(int x,int y){
if(g[x][y] || x < 0 || x >= 5 || y < 0 || y >= 5) return false;
return true;
}
void bfs(){
queue<node> q;
q.push({0,0});
vis[0][0] = true;
while(!q.empty()){
top = q.front();
q.pop();
if(top.x == 4 && top.y == 4){//输出结果
stack<node> s;
cur = top;
while(cur.x || cur.y){
s.push(cur);
cur = record[cur.x][cur.y];
}
cout << "(0, 0)" << endl;
while(!s.empty()){
cur = s.top();
s.pop();
cout << '(' << cur.x << ", " << cur.y << ')' << endl;
}
return;
}
for(int i = 0; i < 4; i++){
cur.x = top.x + dir[0][i];
cur.y = top.y + dir[1][i];
if(judge(cur.x,cur.y) && !vis[cur.x][cur.y]){
vis[cur.x][cur.y] = true;
q.push(cur);
record[cur.x][cur.y] = top;
}
}
}
}
int main(void){
ios_base::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
for(int i = 0; i < 5; i++){
for(int j = 0; j < 5; j++) cin >> g[i][j];
}
bfs();
return 0;
}
L - Oil Deposits
'@ 表示石油,每找到一个@ - bfs标记相连的@,计算bfs次数。
int ans,n,m,dir[3] = {0,-1,1};
string g[105];
bool vis[105][105];
struct node{
int x,y;
}cur,top;
bool judge(node cur){
if(cur.x < 0 || cur.y < 0 || cur.x >= n || cur.y >= m) return false;
if(g[cur.x][cur.y] == '*') return false;
return true;
}
void bfs(int x,int y){
queue<node> q;
q.push({x,y});
vis[x][y] = true;
while(!q.empty()){
top = q.front();
q.pop();
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
cur.x = top.x + dir[i];
cur.y = top.y + dir[j];
if(judge(cur) && !vis[cur.x][cur.y] && (i | j)){
vis[cur.x][cur.y] = true;
q.push(cur);
}
}
}
}
}
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
while(cin >> n >> m){
if(!n && !m) break;
memset(vis, false, sizeof vis);
ans = 0;
for(int i = 0; i < n; i++) cin >> g[i];
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(g[i][j] == '@' && !vis[i][j]){
bfs(i,j);
++ans;
}
}
}
cout << ans << endl;
}
return 0;
}
M - 非常可乐
大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为。因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多。但seeyou的手中只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升 (正好装满一瓶) ,它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。聪明的ACMER你们说他们能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出"NO"。
-
s需要均分,必须为偶数
-
3个杯子互相倒,每种状态有六种可能的倒法:n->m n->s m->n m->s s->n s->m,bfs。。。
//s->n n未满 s有剩余
if(top.s && top.n<n){
//s剩余量可不可以使n填满
if(top.s >= n-top.n) node.n = n,node.s = top.s-n+top.n;
else node.n = top.n+top.s,node.s = 0;
node.m = top.m;
node.time = top.time+1;
//每种状态入队一次
if(!vis[node.n][node.m]){
q.push(node);
vis[node.n][node.m] = true;
}
}
- 数学做法:...
N - Find a way
Y和M要在‘@’见面,每走一步耗时十一分钟,初始时y m位于两个位置。两人要去的‘@’总耗时最小。
-
‘@’有多个,对每一个跑一遍bfs()求最小总步数会超时.... -
y,m各自bfs(),记录到达各个‘@’的时间,寻找到达‘@’的步数总和最小的点...
const int INF = 0x3f3f3f3f;
int n,m,ans,book[2][210][210],dir[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
struct node{
int x,y,step;
}cur,top;
vector<pair<int,int>> posi;
string g[205];
bool vis[205][205];
bool judge(int x, int y){
if(x < 0 || x >= n || y < 0 || y >= m) return false;
if(g[x][y] == '#') return false;
return true;
}
void bfs(int f, int x, int y){
memset(vis,false,sizeof(vis));
vis[x][y] = true;
queue<node> q;
q.push({x,y,0});
while(!q.empty()){
top = q.front();
q.pop();
cur.step = top.step+1;
if(g[top.x][top.y] == '@'){//'@'所在位置记录一遍
book[f][top.x][top.y] = top.step;
if(f) posi.push_back(make_pair(top.x,top.y));
}
for(int i = 0; i < 4; i++){
cur.x = top.x + dir[i][0];
cur.y = top.y + dir[i][1];
if(judge(cur.x, cur.y) && !vis[cur.x][cur.y]){
vis[cur.x][cur.y] = true;
q.push(cur);
}
}
}
}
int main(void){
ios_base::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
while(cin >> n >> m){
for(int i=0;i<n;i++) cin >> g[i];
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(g[i][j] == 'Y') bfs(1,i,j);
if(g[i][j] == 'M') bfs(0,i,j);
}
}
ans = INF;
for(int i = 0; i < posi.size(); i++){//最小总步数
ans = min(ans,book[0][posi[i].first][posi[i].second] + book[1][posi[i].first][posi[i].second]);
}
posi.clear();
cout << ans * 11 << endl;
}
return 0;
}
原文地址:https://www.cnblogs.com/honey-cat/p/12924720.html
- Tensorflow之 CNN卷积神经网络的MNIST手写数字识别
- 你听过算法也是可以贪心的吗?
- 前后端分离ueditor富文本编辑器的使用-Java版本
- Golang语言社区--Go语言基础第六节函数
- Golang语言社区--理解 go interface 的 5 个关键点
- 得到一个物种所有基因的TSS(转录起始位点)区域的bed文件。
- 如何选择聚类模块数目
- 谁能告诉我,这数据测毁了么?
- 计算资源及编程-仅针对生信人员
- 从WGS测序得到的VCF文件里面提取位于外显子区域的【直播】我的基因组84
- 基因组重测序的unmapped reads assembly探究 【直播】我的基因组86
- Centos 下非 Root 安装 Microsoft R Open
- 下载TCGA所有癌症的maf文件做signature分析
- 比对NR库看看物种分布【直播】我的基因组88
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Real-time Xenomai 3 example 1
- Electron 常见问题收录II
- SQL性能调优技巧
- Linux查看CUDA版本以及cudnn版本号
- 数据结构算法操作试题(C++/Python)——最长有效括号
- 数据结构算法操作试题(C++/Python)——两两交换链表中的节点
- 数据结构算法操作试题(C++/Python)——最大子序和
- 数据结构算法操作试题(C++/Python)——四数之和
- 数据结构算法操作试题(C++/Python)——在排序数组中查找元素的第一个和最后一个位置
- 数据结构算法操作试题(C++/Python)——搜索旋转排序数组
- 数据结构算法操作试题(C++/Python)——最后一个单词的长度
- IDEA 自动生成类注释和方法注释
- 包管理工具yarn的安装和使用详细介绍
- redis学习(九)
- 模型性能提升操作