深度优先搜索提高

卒的遍历

在一张n*m的棋盘上(如6行7列)的最左上角(1,1)的位置有一个卒。该卒只能向下或者向右走,且卒采取的策略是先向下,下边走到头就向右,请问从(1,1)点走到(n,m)点可以怎样走,输出这些走法。

输入

两个整数n,m代表棋盘大小(3=<n<=8,3<=m<=8)

输出

卒的行走路线

样例输入
3 3
样例输出
1:1,1->2,1->3,1->3,2->3,3
2:1,1->2,1->2,2->3,2->3,3
3:1,1->2,1->2,2->2,3->3,3
4:1,1->1,2->2,2->3,2->3,3
5:1,1->1,2->2,2->2,3->3,3
6:1,1->1,2->1,3->2,3->3,3
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,ans=0,vis[15][15];
int dx[4]= {1,0},dy[4]= {0,1};
struct te{
    int dx;
    int dy;
};
te a[20];
void dfs(int x,int y,int step){
    if(x==n&&y==m) {
        a[step].dx=x;
        a[step].dy=y;
        ans++;
        cout<<ans<<":"<<a[0].dx<<","<<a[0].dy;
        for(int i=1;i<=step;i++)
            cout<<"->"<<a[i].dx<<","<<a[i].dy;
        cout<<endl;
    }
    vis[x][y]=1;
    a[step].dx=x;
    a[step].dy=y;
    for(int i=0;i<2;i++){
        int tx=x+dx[i],ty=y+dy[i];
        if(tx>0&&ty>0&&tx<=n&&ty<=m&&vis[tx][ty]==0) {
            step++;
            dfs(tx,ty,step);
            vis[tx][ty]=0;
            step--;
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    dfs(1,1,0);
    return 0;
}

马的遍历

中国象棋半张棋盘如图(a)所示。马自左下角往右上角跳。今规定只许往右跳,不许往左跳,且要求马跳的方式按照(b)图顺时针深度优先递归。比如图(a)中所示为一种跳行路线。如果马要从0,0点,跳到4,8点,前6种跳法的打印格式如下,请参考前6种跳的方式,输出马从0,0点到4,8点所有可能的跳的路线。

1:0,0->2,1->4,2->3,4->4,6->2,7->4,8
2:0,0->2,1->4,2->3,4->1,5->3,6->4,8
3:0,0->2,1->4,2->3,4->1,5->2,7->4,8
4:0,0->2,1->4,2->2,3->4,4->3,6->4,8
5:0,0->2,1->4,2->2,3->4,4->2,5->4,6->2,7->4,8
6:0,0->2,1->4,2->2,3->4,4->2,5->0,6->2,7->4,8

...

代码:
#include<bits/stdc++.h>
using namespace std;
int a[2][15],cnt;
int dx[4]={2,1,-1,-2};
int dy[4]={1,2,2,1};
bool check(int fx,int fy){
	if(fx<=4&&fx>=0&&fy<=8&&fy>=0)
		return 1;	
	return 0;
}
void pr(int n,int cnt){
	cout<<cnt<<":";
	for(int i=1;i<n;i++){
		if(i!=n-1)
			printf("%d,%d->",a[0][i],a[1][i]);
		else 
			printf("%d,%d",a[0][i],a[1][i]);
	}printf("\n");
}
void dfs(int n,int x,int y){
	if(x==4&&y==8){
		cnt++;pr(n,cnt);
	}	
	else{
		for(int i=0;i<4;i++){
			int fx=x+dx[i];
			int fy=y+dy[i];
			if(check(fx,fy)){
				a[0][n]=fx;
				a[1][n]=fy;
				dfs(n+1,fx,fy);
			}
		}		
	}
}

int main(){
	a[0][0]=0,a[1][0]=0,a[0][1]=0,a[1][0]=0;
	dfs(2,0,0);
} 

小X学游泳

小X想要学游泳。
这天,小X来到了游泳池,发现游泳池可以用N行M列的格子来表示,每个格子的面积都是1,且格子内水深相同。
由于小X刚刚入门,他只能在水深相同的地方游泳。为此,他把整个游泳池看成若干片区域,如果两个格子相邻(上下左右四个方向)且水深相同,他就认为它们属于同一片区域。
小X想知道最大的一片区域面积是多少,希望你帮帮他。

输入

第一行包含用一个空格隔开的两个整数N,M。(1≤N,M≤100)
接下来N行,每行包含M个 1到9的数字,表示每个格子的水深

输出

第一行包含一个整数,表示最大的一片区域面积。

样例输入
3 3
124
224
152
样例输出
3
提示

数据范围

对于30%的数据,1≤N,M≤3。
对于60%的数据,1≤N,M≤10。
对于 100%的数据,1≤N,M≤100。

代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,ans=1,bj[105][105],sum;
int dx[4]={-1,0,0,1},dy[4]={0,-1,1,0};
char a[105][105];
void dfs(int x,int y,char temp){
    bj[x][y]=1;
    sum++;
    ans=max(ans,sum);
    for(int i=0;i<4;i++){
        int tx=x+dx[i],ty=y+dy[i];
        if(tx>=0&&ty>=0&&tx<n&&ty<m&&bj[tx][ty]==0&&a[tx][ty]==temp)
            dfs(tx,ty,temp);
    }
}
int main() {
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++) {
        cin>>a[i];
    }
    for(int i=0;i<n;i++) {
        for(int j=0;j<m;j++) {
            if(!bj[i][j]){
                sum=0;
                dfs(i,j,a[i][j]);
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

组合的输出

排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且r < = n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取r个数。
例如n = 5 ,r = 3 ,所有组合为:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5

输入

一行两个自然数n、r ( 1 < n < 21,1 < = r < = n )。

输出

所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,所有的组合也按字典顺序。

样例输入
5 3
样例输出
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
代码:
#include<bits/stdc++.h>
using namespace std;
void out(int a[],int n)
{
    for(int i=1;i<=n;i++)
        cout<<a[i]<<" ";
    cout<<endl;
}
bool pd(int a[],int n,int r)
{
    if(a[r]<n){
        a[r]++;
    }
	else
    {
        int i=1;
        while(a[r-i]==n-i&&r-i>0){
            i++;
        }
        if(r-i==0)return false;
        a[r-i]++;
        while(i){
            a[r-i+1]=a[r-i]+1;
            i--;
        }
    }
    return true;
}
int n,r;
int a[100];
int main()
{ 
    cin>>n>>r;
	for(int i=1;i<=r;i++)
        a[i]=i;
    do
    {
        out(a,r);
    }
	while(pd(a,n,r));      
    return 0;
} 

算24点

给出n组4个整数,请问有多少组整数,在不改变顺序,且不加入括号的情况下,可以通过+ - *三种运算,得到24。

比如1 2 3 4四个数,可以通过如下的方法得到24:1*2*3*4=24。

而20 30 40 50四个数,在不改变顺序、不添加括号的情况下,通过+ - *三种运算是无法获得24的。  

输入

第1行有一个整数n;(2<=n<=100)

接下来n行,每行有4个整数ai(1<=ai<=100)

输出

输出一个整数,代表有几组数能够通过题目的规则计算得到24。

样例输入
4
1 2 3 4 
10 20 30 40
50 60 70 80
9 1 8 2
样例输出
2
代码:
//愚蠢的枚举
#include<bits/stdc++.h>
using namespace std;
int main(){
	int n,a[110],sum=0;
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=4;j++){
			cin>>a[j]; 
		}
		if(a[1]+a[2]+a[3]+a[4]==24){
			sum++;
		}
		else if(a[1]+a[2]+a[3]-a[4]==24){
			sum++;
		}
		else if(a[1]+a[2]+a[3]*a[4]==24){
			sum++;
		}
		else if(a[1]+a[2]-a[3]+a[4]==24){
			sum++;
		}
		else if(a[1]+a[2]-a[3]-a[4]==24){
			sum++;
		}
		else if(a[1]+a[2]-a[3]*a[4]==24){
			sum++;
		}
		else if(a[1]+a[2]*a[3]+a[4]==24){
			sum++;
		}
		else if(a[1]+a[2]*a[3]-a[4]==24){
			sum++;
		}
		else if(a[1]+a[2]*a[3]*a[4]==24){
			sum++;
		}
		else if(a[1]-a[2]+a[3]+a[4]==24){
			sum++;
		}
		else if(a[1]-a[2]+a[3]-a[4]==24){
			sum++;
		}
		else if(a[1]-a[2]+a[3]*a[4]==24){
			sum++;
		}
		else if(a[1]-a[2]-a[3]+a[4]==24){
			sum++;
		}
		else if(a[1]-a[2]-a[3]-a[4]==24){
			sum++;
		}
		else if(a[1]-a[2]-a[3]*a[4]==24){
			sum++;
		}
		else if(a[1]-a[2]*a[3]+a[4]==24){
			sum++;
		}
		else if(a[1]-a[2]*a[3]-a[4]==24){
			sum++;
		}
		else if(a[1]-a[2]*a[3]*a[4]==24){
			sum++;
		}
		else if(a[1]*a[2]+a[3]+a[4]==24){
			sum++;
		}
		else if(a[1]*a[2]+a[3]-a[4]==24){
			sum++;
		}
		else if(a[1]*a[2]+a[3]*a[4]==24){
			sum++;
		}
		else if(a[1]*a[2]-a[3]+a[4]==24){
			sum++;
		}
		else if(a[1]*a[2]-a[3]-a[4]==24){
			sum++;
		}
		else if(a[1]*a[2]-a[3]*a[4]==24){
			sum++;
		}
		else if(a[1]*a[2]*a[3]+a[4]==24){
			sum++;
		}
		else if(a[1]*a[2]*a[3]-a[4]==24){
			sum++;
		}
		else if(a[1]*a[2]*a[3]*a[4]==24){
			sum++;
		}
	}
	cout<<sum;
	return 0;
}
  • 17
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值