机试笔记--搜索
一.枚举
例题一 百鸡问题
#include<bits/stdc++.h> using namespace std; int main(){ int n; while (cin>>n) { for (int i = 0; i <= 100; i++) { for (int j = 0; j <= 100 - i; j++) { int m = 100 - i - j; if (i * 5 + 3 * j + (double) 1 / 3 * m > n) break; else cout << "x=" << i << ",y=" << j << ",z=" << m << endl; } } } return 0; }
例题二 老比尔
N _XYZ_,N是火鸡的数量,现在不知道价格的第五位和第一位,求一只火鸡的价格
有多个满足条件的价格时选择价格最高的。
假设一只火鸡的价格为整数,总价为5位数
#include <bits/stdc++.h> using namespace std; int main(void){ int n, a, b, c, d, e, bcd, abcde; while(cin >>n >>a >>b >>c){ bool flag = false; bcd = a*1000 + b*100 +c*10; for(int a=9; a>=1; a--){//倒着搜索,保证是最大值 for(int e=9; e>=0; e--){ abcde = a*10000 + bcd + e; if(abcde%n==0){ flag = true; printf("%d %d %d\n", a, e, abcde/n); break; } } if(abcde%n==0) break; } if(!flag) cout <<0 <<endl; //未找到返回0 } return 0; }
广度优先搜索
例题:玛雅人的密码
玛雅人有一种密码,如果字符串中出现连续的2012四个数字就能解开密码。给一个长度为N的字符串,(2=<N<=13)该字符串中只含有0,1,2三种数字,问这个字符串要移位几次才能解开密码,每次只能移动相邻的两个数字。例如02120经过一次移位,可以得到20120,01220,02210,02102,其中20120符合要求,因此输出为1.如果无论移位多少次都解不开密码,输出-1。
输入:输入包含多组测试数据,每组测试数据由两行组成。
第一行为一个整数N,代表字符串的长度(2<=N<=13)。
第二行为一个仅由0、1、2组成的,长度为N的字符串。
输出:输出最少的移位次数,没有,输出-1
分析
- 将所有可能的字符串列举出来,然后判断是否有包含“2012”的
- 又要求输出最少的移位次数,所以应该以图的形式列举出来,然后按照广度优先搜索的方式进行遍历(因为要求的是最少的移位次数)
- 建立这张图的方式:将源字符串作为第一个节点, 然后将它的移位字符串作为邻接点即可.
#include <bits/stdc++.h> using namespace std; string init; int N; typedef struct Node { string s; int step; }Node; int bfs() { Node start; start.s=init,start.step=0; queue<Node> q; q.push(start); map<string,int> m; m[init]=1; while(!q.empty()){ Node temp=q.front(); q.pop(); if(temp.s.find("2012")!=temp.s.npos) return temp.step; for(int i=0;i<N-1;i++){ string now = temp.s; char a; a=now[i]; now[i]=now[i+1]; now[i+1]=a; Node node; node.s=now,node.step=temp.step+1; if(m[now]==0){ q.push(node); m[now]=1; } } } return -1; } int main() { while(cin>>N>>init){ cout << bfs() <<endl; } return 0; }
广度优先搜索的要点:
1.需要有一个一维或二维数组,或者是哈希表来记录是否访问过某节点
2.在while(!q.empty())中如果找到,那么就返回,一般是返回搜索的次数
3.在将周围的节点进队时要判断这个节点是否访问,未访问的话进队并且将这个节点标记