9.29-分支限界法(//加1乘2平方//电子老鼠闯迷宫//农场灌溉问题//满足条件的排列数)

1.加1乘2平方

描述:最简单的队列的使用
#include <iostream>
#include <queue>
using namespace std;

queue<int> q1;
int main()
{
int temp, x;
q1.push(5);//入队
q1.push(8);//入队
temp = q1.front();//访问队首元素
q1.pop();//出队
q1.empty();//判队列是否为空
q1.back();//返回队尾元素
q1.size();//返回队列长度
}

给定两个正整数m、n,问只能做加1、乘2和平方这三种变化,从m变化到n最少需要几次

输入:输入两个10000以内的正整数m和n,且m小于n

输出:输出从m变化到n的最少次数

输入样例

1 16

输出样例

3

#include<iostream>
#include<queue>
using namespace std;

void dfs(int k);
int doit(int u, int i);

queue<int> q;
bool used[10005];
int n, m;
int step[10005];

int main(){
     cin >> n >> m;
	 for(int i = n+1; i <= m; i++){
	     used[i] = true;
	 }
	 step[n] = 0;
	 used[n] = false;
	 q.push(n);
	 dfs(n);
}

void dfs(int k){
	int u, v;
	int flag;
	while(!q.empty()){
		flag = 0;
		u = q.front();
		q.pop();
		for(int i = 0; i < 3; i++){
		    v = doit(u, i);
		    if(v == m){
		    	cout << step[u] +1 << endl;
		    	flag = 1;
		    	break;
		    }
		    else if(v < m && used[v]){
			    q.push(v);
			    used[v] = false;
				step[v] = step[u] + 1;
			}
	    }
	    if(flag){
	    	break;
	    }
	}
}

int doit(int u, int i){
	if(i == 0){
	    return(u+1);
	}
	else if(i == 1){
	    return(2*u);
	}
	else{
	    return(u*u);
	}
}

 

2.电子老鼠闯迷宫

描述:有一只电子老鼠被困在如下图所示的迷宫中。这是一个12*12单元的正方形迷宫,黑色部分表示建筑物,白色部分是路。电子老鼠可以在路上向上、下、左、右行走,每一步走一个格子。现给定一个起点S和一个终点T,求出电子老鼠最少要几步从起点走到终点。

输入:本题包含一个测例。在测例的第一行有四个由空格分隔的整数,分别表示起点的坐标S(x.y)和终点的坐标T(x,y)。从第二行开始的12行中,每行有12个字符,描述迷宫的情况,其中'X'表示建筑物,'.'表示路.

输出:输出一个整数,即电子老鼠走出迷宫至少需要的步数。

输入样例

2 9 11 8
XXXXXXXXXXXX
X......X.XXX
X.X.XX.....X
X.X.XX.XXX.X
X.X.....X..X
X.XXXXXXXXXX
X...X.X....X
X.XXX...XXXX
X.....X....X
XXX.XXXX.X.X
XXXXXXX..XXX
XXXXXXXXXXXX

输出样例

28

#include<iostream>
#include<queue>
using namespace std;

void init();
void dfs();
int cando(int xu, int yu, int i);

struct address{
	queue<int> row;
	queue<int> col;
}address;

char map[12][12];
bool used[12][12];
int xf, yf, xt, yt;
int step[12][12];
int x[4] = {0, 1, 0, -1};
int y[4] = {-1, 0, 1, 0};

int main(){
     init();
	 dfs();
}

void init(){
    int i, j;
	cin >> xf >> yf >> xt >> yt;
	for(i = 0; i < 12; i++){
		for(j = 0; j < 12; j++){
		    cin >> map[i][j];
			if(map[i][j] == 'X'){
			    used[i][j] = false;
			}
			else{
				used[i][j] = true;
		}
	}
	used[xf-1][yf-1] = false;
	step[xf-1][yf-1] = 0;
	address.row.push(xf-1);
	address.col.push(yf-1);
    }
}

void dfs(){
	int xu, yu, xv, yv;
	while(!address.row.empty()){
	    xu = address.row.front();
		yu = address.col.front();
		address.row.pop();
		address.col.pop();
		if(xu == xt-1 && yu == yt-1){
		    cout << step[xu][yu] << endl;
		}
		else{
			for(int i = 0; i < 4; i++){
				if(cando(xu, yu, i)){
				    xv = xu + x[i];
					yv = yu + y[i];
					address.row.push(xv);
					address.col.push(yv);
					used[xv][yv] = false;
					step[xv][yv] = step[xu][yu] +1;
				}
			}
		}
	}
}

int cando(int xu, int yu, int i){
    int xv, yv;
	xv = xu + x[i];
	yv = yu + y[i];
	if(xv < 0 || xv >=12 || yv < 0 || yv >=12 ||!used[xv][yv]){
	    return 0;
	}
	else{
	    return 1;
	}
}

 

3.农场灌溉问题

描述:

一农场由图所示的十一种小方块组成,蓝色线条为灌溉渠。若相邻两块的灌溉渠相连则只需一口水井灌溉。

输入:

给出若干由字母表示的最大不超过50×50具体由(m,n)表示,的农场图

输出:

编程求出最小需要打的井数。每个测例的输出占一行。当M=N=-1时结束程序。

输入样例:

2 2

DK

HF

3 3

ADC

FJK

IHE

-1 -1

输出样例:

2

3

#include<iostream>
#include<queue>
using namespace std;

queue <char> q;

int m, n;
int ans;
char map[51][51];
bool canuse[51][51];
int row[4] = {0, 1, 0, -1};
int col[4] = {-1, 0, 1, 0};
int cando[11][4] = {1, 0, 0, 1,
                    0, 0, 1, 1,
					1, 1, 0, 0,
					0, 1, 1, 0,
					0, 1, 0, 1,
					1, 0, 1, 0,
					1, 0, 1, 1,
					1, 1, 0, 1,
					1, 1, 1, 0,
					0, 1, 1, 1,
					1, 1, 1, 1};

void search(int nx, int ny);
bool judge(char w, int vx, int vy, int i);

int main(){
	int i, j;
	int cnt;
	char tmp;
	while(cin >> m >> n){
		//输入为两个-1时退出循环
		if(m == -1 && n == -1){
		    break;
		}
		//输入灌溉渠地图
		for(i = 0; i < m; i++){
			for(j = 0; j < n; j++){
			    cin >> map[i][j];
				canuse[i][j] = true;
			}
		}
		ans = 0;   //初始化所需井数
		for(i = 0; i < m; i++){
			for(j = 0; j < n; j++){
			    if(canuse[i][j]){
			    	q.push(map[i][j]);
			    	canuse[i][j] = false;
			        search(i, j);
				    ans++;
			    }
			}
		}
		cout << ans << endl;
	}
	return 0;
}

void search(int nx, int ny){
	int i, vx, vy;
	char tmp;
	while(!q.empty()){
	    tmp = q.front();
		q.pop();
		for(i = 0; i < 4; i++){
			vx = nx + row[i];
			vy = ny + col[i];
			if(judge(tmp, vx, vy, i)){
			    q.push(map[vx][vy]);
				canuse[vx][vy] = false;
				search(vx, vy);
			}
		}
	}
}

bool judge(char w, int vx, int vy, int i){
	if(vx < 0 || vy < 0 || vx >= m || vy >= n){
	    return false;
	}
	if(!canuse[vx][vy]){
	    return false;
	}
	int t = w - 65;
	int r  = map[vx][vy] - 65;
	if(cando[t][i] &&cando[r][(i+2)%4]){
		return true;
	}
	return false;
}

 

 

4.满足条件的排列数

描述:给定两个正整数m和n(一般的n小于13,也有n较大m相对很大的数据,n最大21),问1到n这n个数的以1开头的排列有多少个满足条件:任意两个相邻的数的和都大于等于m。

输入:输入两个正整数m和n,

输出:输出满足条件的排列的个数。

输入样例

5 4

输出样例

2

#include<iostream>
using namespace std;

int m, n, cnt = 0;
int arr[30];
int used[30] = {0};

void dfs(int t);

int main(){
    cin >> m >> n;
    arr[0] = 1;

	dfs(1);
	cout << cnt << endl;
}

void dfs(int t){
	if(t == n){
		cnt++;
	}
	else{
		for(int i = 2; i <= n; i++){
			if(!used[i] && arr[t-1] + i >= m){
			    arr[t] = i;
				used[i] = 1;
				dfs(t+1);
				used[i] = 0;
			}
		}
	}
}

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值