第一周 kuangbin 搜索入门

1、棋盘问题 POJ - 1321

//棋盘问题 POJ - 1321 
//思路: 主要从三个限制条件考虑 
//不同行:每一行每一次dfs只取一个位置
//不同列:用一个judge数组储存当次方案中每一列是否已经被占用
//只能在#:遇到#才进入搜索 
#include<algorithm>
#include<stdlib.h>
#include<iostream>
#include<cstring>

using namespace std;
void dfs(int row);

char data[8][8];     //棋盘 
bool judge[8];       //记录不同列是否已经有棋子 
int n, k, ans, cnt;

int main(){
    
    
	cin>>n >>k;
	while (n!=-1 && k!=-1) {
    
    
		if (n == 0) {
    
    
			cout<<0<<endl;
			cin >>n >>k;
			continue;
		}
		int i;
		for (i=0; i<n; i++) {
    
         //输入棋盘情况 
			for (int j=0; j<n; j++){
    
    
				cin>>data[i][j];
			}
		}
		ans = 0;
		cnt = 0;
		memset(judge, true, sizeof(judge));  //将bool数组judge初始化为false 
		dfs(0);
		cout<<ans <<endl; 
		cin>>n >>k;
	} 
	return 0;
}

void dfs(int row) {
    
    
	if (cnt == k) {
    
         //找到满足要求的k个位置 
		ans ++;
		return;
	}
	if (row >= n) return;  //超出棋盘的范围 
	for (int i=0; i<n; i++) {
    
    
		if (judge[i] && data[row][i]=='#') {
    
      //i列没有落下棋子 且 棋盘row行i列是# 
			cnt ++;                           //cnt判断是否已经落下最后一颗棋子 
			judge[i] = false;                 //该列不可再用 
			dfs (row+1);                      //搜索下一行 
			cnt --;                           //递归回来后,相当于此时棋子不落入 row行i列 这个位置,需要更新cnt和judge 
			judge[i] = true;
		}
		
	}
	dfs(row+1);             //当k<n时,比如n==4,k==1,则棋盘的第二行在for循环虽然有递归进入,但是在dfs的一开始就被return了 
}

2、Dungeon Master POJ - 2251

//思路:在地图map上,从S进入后,判断上下左右前后六个方向是否能走,能则将位点放进队列que里,只要que不为空,
//则一直每次取出一个位点,并判断是否能从该位点再接着go,一直到遇到E则return。
//因为六个方向中,每一次放入队列都是在当次判断位点是否能go完成,所以不需要min(ans,time);
//【注意】每一次走过后把 . 变成 #
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;

char map[33][33][33]; //地图
int l,r,c,i,j,k,bx,by,bz,ans;
int ne[6][3] = {
    
    {
    
    0,0,1},{
    
    0,0,-1},{
    
    0,1,0},{
    
    0,-1,0},{
    
    1,0,0},{
    
    -1,0,0}}; //下一步坐标:向右/左/前/后/上/下
 
struct stu //位点:坐标以及到达此处的最短步数
{
    
    
    int x,y,z,step;
};
bool go(stu st) //判断能否走
{
    
    
    if(st.x<0 || st.z<0 || st.y<0 || st.y>=r || st.z>=c || st.x>=l || map[st.x][st.y][st.z] =='#')
		return false;
    return true;
}
int bfs(int x,int y,int z)
{
    
    
    map[x][y][z] = '#';   //关闭入口
    int time,xx,yy,zz;
    queue<stu> que; //队列
    stu st; //
    st.x = x;
    st.y = y;
    st.z = z;
    st.step = 0;
    que.push(st);   //将起始位点放入队列
 
    while(!que.empty())
    {
    
    
        st=que.front();
        que.pop();

        xx = st.x;
        yy = st.y;
        zz = st.z;
        time = st.step;
        for(i=0;i<6;i++)
        {
    
    
            st.x = xx+ne[i][0];
            st.y = yy+ne[i][1];
            st.z = zz+ne[i][2];
            if(!go(st))  //碰到#或溢出continue
            {
    
    
                continue;
            }
            if(map[st.x][st.y][st.z]=='E') //到达终点
            {
    
    
                return time+1;
            }
            st.step = time+1;
            que.push(st);         //放入下一步位点
            map[st.x][st.y][st.z] = '#';
        }
    }
    return 0; //不能实现
}
int main()
{
    
    
    int i,j,k;
    while(cin>>l>>r>>c && l && r && c) {
    
    
		int x0, y0, z0;   //起始坐标
        for(i=0;i<l;i++) {
    
    
            for(j=0;j<r;j++) {
    
    
                for(k=0;k<c;k++) {
    
    
					cin>>map[i][j][k];
                    if(map[i][j][k]=='S') {
    
      //入口
						x0 = i;
						y0 = j;
						z0 = k;
                    }
                }
            }
			getchar();
        }
		ans = bfs(x0, y0, z0);
		if (ans) {
    
    
			cout<<"Escaped in "<<ans<<" minute(s)."<<endl;
		}
		else {
    
    
			cout<<"Trapped!"<<endl;
		}
    }
    return 0;
}

3、Catch That Cow POJ - 3278

//Catch That Cow POJ - 3278
/*
思路:对于初始值n,有+1、-1、*2三种操作,如果当次操作得不到k,就将操作
后的三个数放进队列(已经出现过的数、*2后过大的数除外),循环往复直到==k。
*/

#include<algorithm>
#include<stdlib.h>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;

int n,k,ans;
int book[100105];  //查阅是否重复

struct val
{
    
    
    int x,time;   //x--值   time--操作了几次才到这个值
};

int bfs(){
    
    
	queue<val> que;
	//que.push(st);   //将起始位点放入队列
    //st=que.front(); //获得
    //que.pop();      //弹出
	val va;
	va.x = n;
	va.time = 0;
	que.push(va);
	while(!que.empty()) {
    
    
		va = que.front();
		que.pop();
		if(va.x+1==k || va.x-1==k || va.x*2==k) return va.time+1;  //到达致远星
		//移动+1
		if (va.x+1 != k && book[va.x+1]==0) {
    
      //用book检查是否已经出现过
			val temp;
			temp.x = va.x + 1;
			temp.time = va.time + 1;
			book[temp.x] = 1;
			que.push(temp);
		}
		//移动-1
		if (va.x-1 != k && va.x-1>=0 && book[va.x-1]==0) {
    
    
			val temp;
			temp.x = va.x - 1;
			temp.time = va.time + 1;
			book[temp.x] = 1;
			que.push(temp);
		}
		//跃迁*2
		if (va.x * 2 <= k+5 && book[va.x*2]==0) {
    
      //va.x*2过大无意义
			val temp;
			temp.x = va.x * 2;
			temp.time = va.time + 1;
			book[temp.x] = 1;
			que.push(temp);
		}
	}
}

int main(){
    
    
	cin>>n>>k;
	book[n] = 1;
	if(n!=k){
    
    
		ans = bfs();
	}
	cout<<ans<<endl;
	return 0;
}

4、POJ 3279(更新ing)

5、Find The Multiple POJ - 1426

//Find The Multiple POJ - 1426
/*
思路:一开始以为不超过100位是要用高精,但是在对高精数组进行元素只有
01的变换+求模,发现会更麻烦。
而要求的倍数m只由0、1组成,且最高位必定为1,所以由二进制串的特点,凭借
k=1 变化为 k = k*10 或者 k = k*10+1,可以依次得到位数不断增加的可能符合
要求的m,再对m % n,若==0,则返回该值,不满足则继续搜索。

注意:由于是用long long储存每一个可能满足要求的k,所以需要额外判断是否
超过20次操作,以防溢出。
由于dfs用了递归,另外开一个bool变量,在找到ans后中断递归。
*/
#include<algorithm>
#include<stdlib.h>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;

int n;
long long ans;
bool bo = false;  //是否中断递归

void dfs(int cnt, long long k){
    
      
	if(cnt>=20 || bo) return;   //k过大了 || 已经找到ans了
	if (k % n == 0) {
    
       //求模判断是否满足要求
		ans = k;
		bo = true;
		return;
	}
	dfs(cnt+1, k*10);
	dfs(cnt+1, k*10+1);
}

int main(){
    
    
	while(cin>>n && n!=0) {
    
    
		ans = 0;
		bo = false;
		dfs(1,1);     //dfs(1,0)无意义
		cout<<ans<<endl;
	}
	return 0;
}

6、Prime Path POJ - 3126

//Prime Path POJ - 3126
/*
思路:和上面的bfs类似,只不过需要在改变位数时,注意不止是要第一次
出现才放进队列,还必须是素数。
*/
#include<algorithm>
#include<stdlib.h>
#include<iostream>
#include<cstring>
#include<queue>

using namespace std;

int table[10004];   //素数表
int book[10004];    //查询表--是否已经有相同的va.x进入过队列--防止死循环/不必要的重复
int sta,ending;     //不能命名为end,会报错

struct val
{
    
    
    int x,time;  
};
//制作素数表
void makeTable(){
    
    
	for(int i=2; i<103; i++){
    
    
		if (table[i] == 0) {
    
    
			for(int j=i*i; j<10004; j+=i) {
    
    
				if(table[j] == 0){
    
    
					table[j] = i;
				}
			}
		}
	}
}

void bfs(){
    
    
	val va;
	va.x = sta;
	va.time = 0;
	queue<val> que;
	//que.push(st);   //将起始位点放入队列
    //st=que.front(); //获得
    //que.pop();      //弹出
	que.push(va);
	book[va.x] = 1;
	while(!que.empty()){
    
    
		va = que.front();
		que.pop();
		for(int i=0; i<4; i++){
    
    
			for(int j=0; j<10; j++){
    
    
				if(i==0 && j==0) continue;  //首位不可为0
				int num ;
				if (i==0){
    
              //改变千位
					num = va.x - va.x/1000*1000 + j*1000;
				}
				else if(i==1){
    
          //改变百位
					num = va.x - (((va.x/100) %10)*100) + j*100;
				}
				else if(i==2){
    
          //改变十位
					num = va.x - ((va.x/10)%10)*10 + j*10;
				}
				else if(i==3){
    
          //改变个位
					num = va.x - va.x%10 + j;
				}
				if (num == ending){
    
      //转换完毕
					cout<<va.time+1<<endl;
					return;
				}
				if(book[num]==0 && table[num]==0){
    
      //未出现+是素数==》加入队列
					val temp;
					temp.x = num;
					temp.time = va.time+1;
					que.push(temp);
					book[num] = 1;     //更新查询表
				}
			}
		}
	}
	cout<<"Impossible"<<endl;    //没有在while里面return说明无法转换
}

7、Shuffle’m Up POJ - 3087

//Shuffle'm Up POJ - 3087 
/*
思路:多模拟几组交换情况后,可以发现对于length==n的s1和s2,在交叉了
2*n-1次后又形成了原先s1+s2的字符串,所以最多只需要操作2*n-1次。
如果操作期间形成了s,则输出数组编号+操作次数,反之输出数组编号+-1.
*/
#include<algorithm>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<queue>
using namespace std;


int main(){
    
    
	int t;
	cin>>t;
	for(int i=1; i<=t; i++){
    
    
		int n, ans=0;
		string str0, str1, str;
		cin>>n>>str0>>str1>>str;
		bool bo = false;    
		for (int j=0; j<2*n-1; j++){
    
    
			string temp = str;   //交叉后形成的字符串
			int index0=0, index1=0;
			for(int k=1; k<=2*n; k++) {
    
    
				if(k%2 == 1){
    
        //拿str1的字符
					temp[k-1] = str1[index1++];
				}
				else{
    
                //拿str0的字符
					temp[k-1] = str0[index0++];
				}
			}
			if(str == temp){
    
         //与目标字符串相同
				cout<<i<<" "<<ans+1<<endl;
				bo = true;       //防止输出-1
				break;
			}
			else {
    
    
				ans ++;
				str0 = temp.substr(0,n);
				str1 = temp.substr(n,n);
			}
		}
		if(!bo) cout<<i<<" "<<-1<<endl;
	}
	return 0;
}

8、POJ 3414(更新ing)

9、FZU 2150(更新ing)

10、UVA 11624(更新ing)

11、迷宫问题 POJ 3984

//迷宫问题 POJ - 3984 
/*
思路:起始位置和终点位置是唯一的,但是由于需要输出最短路径,那么
就需要记录下走的位置。一开始想着在结构体里放一个实例指针,但是好像
在bfs()不能赋值,所以开了一个val way[7][7]实例数组(val实例本身也是
存放坐标),那么每走一步,刚好可以记录上一步的坐标,也不用树或者链表。

注意:边界的位置不能任意向上下左右走,但是判断又比较麻烦,所以可以把
迷宫的地图map数组开大一点点,数组遍历从1开始,而map[x][0]、map[0][y]
等等边界的外侧则直接赋值为1(即不可通过)。
*/
#include<algorithm>
#include<stdlib.h>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;

int map[10][10];     //迷宫
int dir[4][2] = {
    
    {
    
    1,0},{
    
    0,1},{
    
    0,-1},{
    
    -1,0}};  //向下、右、左、上走


struct val   //定义坐标
{
    
    
    int x,y; 
};

val way[7][7];  //在每一个way[i][j]储存上一步的坐标(迷宫每个点只压入队列一次,所以不会冲突)

void bfs(){
    
    
	val va;
	va.x = 5;   //从终点往起始点找最短路径
	va.y = 5;
	queue<val> que;
	que.push(va);
	while(!que.empty()){
    
    
		va = que.front();
		que.pop();
		for(int i=0; i<4; i++){
    
    
			int x = va.x + dir[i][0];  
			int y = va.y + dir[i][1];
			if (map[x][y] == 0){
    
       //遇到0才可以走,遇墙和走过的点不理
				val temp;
				temp.x = x;
				temp.y = y;
				way[x][y] = va;  //记录前一个点的坐标
				map[x][y] = 1;   //将走过的点变成墙,否则会死循环
				if (x==1 && y==1){
    
      //走到起始点了
					return;
				}
				que.push(temp);
			}
		}
	}
}

int main(){
    
    
	memset(map, 1, sizeof(map));   //因为map开大了一点,把边界设置为1的话,就不用考虑是否会超出边界的情况
	for(int i=1; i<=5; i++){
    
    
		for(int j=1; j<=5; j++){
    
    
			cin>>map[i][j];
		}
	}
	bfs();
	int x = 1, y = 1;
	while(true){
    
    
		cout<<"("<<x-1<<", "<<y-1<<")"<<endl;
		if(x==5 && y==5) break;
		int temp = x;     //更新下一步的坐标
		x = way[x][y].x;
		y = way[temp][y].y;
	}
	return 0;
}

12、HDU 1241(更新ing)

13、HDU 1495(更新ing)

14、HDU 2612(更新ing)

猜你喜欢

转载自blog.csdn.net/CSDNWudanna/article/details/108787358