7.2 POJ刷题记录【深搜广搜】

目录

1321 棋盘问题

2698 八皇后问题

2748 全排列

3050 Hopscotch

4070 全排列

4077 出栈序列统计

4103 踩方格

4127 迷宫问题

B Anagram

1164:The Castle

1562:Oil Deposits

1565:Skew Binary


bool check(){}
void dfs(int step)
{
    if(step>n)//判断边界,达到边界则进入if语句
    {
        /*进行一些操作,比如输出*/
        return;//退出递归
    }
    /*尝试每一种可能*/
    {
        if(check()){continue;}//这种可能已经达到要求了
        /*标记*/
        /*使用这种可能*/
        dfs(step+1);//下一轮dfs
        /*恢复标记前状态(回溯的时候要用到)*/
    }
}
 

1321 棋盘问题

#include<cstring>
#include<iostream>
using namespace std; 
int a[10],n,k,first;
int sum;
char map[10][10];
//行由x控制,列由for循环里面的j控制 
void dfs(int x,int step){
	int j;
	if(step==0){ //满足临界条件,即已经遍历完毕 
		sum++;  //拜访种类+1 
		return;
	}
	if(x>=n) return; //“超出范围”只能是行超出范围,因为列控制由j负责
	for(j=0;j<n;j++){
		if(!a[j]&&map[x][j]=='#'){
			a[j]=1;   //表示访问过该列 
			dfs(x+1,step-1);
			a[j]=0; //dfs需要回溯尝试所有情况 
		} 
	}
	dfs(x+1,step);
}
int main(){
	int i,j;
	while(cin>>n>>k&&n!=-1&&k!=-1){	
		memset(a,0,sizeof(a)); //初始化摆放方案记录值、列标记
		sum=0;
		for(i=0;i<n;i++)
		cin>>map[i];	  //二维数组当一维来进行操作(妙啊) 
		dfs(0,k);  //起始坐标为(0,0) 
		cout<<sum<<endl;
	}
	return 0;
}

2698 八皇后问题

#include<cstdio>
#include<cstdlib>
#include<cstring>
int b[10];
int n=8,cnt; 

void print_queen(int b[])
{
    //原题目输出的结果行列互换 
    printf("No. %d\n",cnt);
    for(int i=0;i<8;i++)
    {
        for(int j=0;j<8;j++)
        {
            if(b[i]==j)printf("1 ");
            else printf("0 ");
        }
        printf("\n");
    }
} 

void dfs(int x){
    if(x>=n){
        cnt++;
        print_queen(b); 
    }
    else
    {
    	for(int i=0;i<n;i++) //注意逻辑是对第X行分别第1-8列操作,是最大的外层循环 
    	{
        	bool flag=true;  //注意这一行的位置,不是全局变量,每轮循环都要这样做 
        	b[x]=i;//尝试把第cur行的皇后放在第i列 
        	for(int j=0;j<x;j++)//检查是否和前面的皇后冲突(主对角线用y-x标识,副对角线用x+y标识) 
            	if(b[x]==b[j] || x-b[x]==j-b[j] || x+b[x]==j+b[j])
            	{
                	flag=false;
                	break;
            	}
        	if(flag==true)
            	dfs(x+1);
    	}
	}
}

int main()
{
    dfs(0);
    return 0;
}

2748 全排列

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n;
char a[10],ch[7];
bool visited[10];
void dfs(int dep){    
    if(dep>=n) {          
        for(int i=0;i<n;i++)  cout<<a[i];          
        cout<<endl;        
        return ;  
    }    
    for(int i=0;i<n;i++){        
        if(visited[i]) continue;           
        visited[i]=true;      
        a[dep]=ch[i];      
        dfs(dep+1);    
        visited[i]=false;
    }
}
int main(){    
	scanf("%s",ch);   
	n = strlen(ch);
    dfs(0);    
    return 0;
}
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;

char ch[10];
int main()
{
	scanf("%s",ch);
	do
	{
		printf("%s\n",ch);
	}while(next_permutation(ch,ch+strlen(ch)));
	return 0;
}

3050 Hopscotch

#include <iostream>
#include<cstring>
#include<set>
using namespace std;
int a[5][5];
int i;
set<int> s;
int dis[4][2]={0,1,0,-1,1,0,-1,0};
void dfs(int x,int y,int n,int sum){
	if(n==5){
		s.insert(sum);
		return ;
	}
	for(i=0;i<4;i++){
		int xx=x+dis[i][0];
		int yy=y+dis[i][1];
		if(xx>=0&&yy>=0&&xx<5&&yy<5)   //注意条件! 
			dfs(xx,yy,n+1,sum*10+a[xx][yy]);
	}
}
int main(void){
	int i,j;
	for(i=0;i<5;i++)
		for(j=0;j<5;j++)
			cin>>a[i][j];
	for(i=0;i<5;i++)
		for(j=0;j<5;j++)	
			dfs(i,j,0,a[i][j]);
	printf("%d\n",s.size());  //记得输出结果 
	return 0;
}

4070 全排列

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int n;
int a[8]={1,2,3,4,5,6,7,8},b[8];
int visited[8]={0};
void dfs(int x){
	if(x>=n){
		for(int i=0;i<n;i++){
			cout<<b[i]<<' ';
		}
		cout<<endl;
		return ;
	}
	else{
		for(int i=0;i<n;i++){
			if(visited[i]) continue;
			else{
				visited[i]=1;
				b[x]=a[i];
				dfs(x+1);
				visited[i]=0;
			}
		}			
	}
}

int main(void){
	cin>>n;
	while(n!=0){
		dfs(0);
		cin>>n;
	}
	return 0;
}

4077 出栈序列统计

#include<iostream>
using namespace std;
int n,sum,ans;
void dfs(int out,int in,int not_in){
	if(out==n){
		ans++;
		return;
	}
	if(in>0) dfs(out+1,in-1,not_in);
	if(not_in>0&&in<n) dfs(out,in+1,not_in-1);
}
int main(){
	cin>>n;
	dfs(0,0,n);
	cout<<ans<<endl;
	return 0;
}

4103 踩方格

//http://bailian.openjudge.cn/practice/4103/ 
#include<iostream>
using namespace std;
int visited[100][100];
int a[100][100];
int dis[3][2]={0,1,1,0,-1,0};
int n,sum;
void dfs(int x,int a, int b){
	if(x>=n){
		sum++;
		return ;
	}
	for(int i=0;i<3;i++){
		int aa=a+dis[i][0];
		int bb=b+dis[i][1];
		if(visited[aa][bb]==1) continue;  //要走的路堵死了 
		else{
			visited[a][b]=1;  //站的路没了 
			dfs(x+1,aa,bb);
			visited[a][b]==0; //站的路又有了 
			}
		}
}
int main(void){
	cin>>n;
	dfs(0,50,0);
	cout<<sum;
}
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int visited[20][50]={0};
int dfs(int i,int j,int n){
	if(n==0) return 1;
	visited[i][j]=1;
	int num=0;
	if(!visited[i+1][j]) num+=dfs(i+1,j,n-1);
	if(!visited[i][j+1]) num+=dfs(i,j+1,n-1);
	if(!visited[i][j-1]) num+=dfs(i,j-1,n-1);
	visited[i][j]=0;
	return num;
}
int main(){
	int n;
	cin>>n;
//	memset(visited,0,sizeof(visited));
	cout<<dfs(0,25,n)<<endl;
	return 0;
}
int n,l[20],r[20],u[20];
int main(){
	cin>>n;
	if(n==1) cout<<3;
	else{
		l[1]=r[1]=u[1]=1;
		for(int i=2;i<=n;i++){
			l[i]=l[i-1]+u[i-1];
			r[i]=r[i-1]+u[i-1];
			u[i]=l[i-1]+r[i-1]+u[i-1];
		}
		int ans=l[n]+r[n]+u[n];
		cout<<ans<<endl;
	}
	return 0;
}

4127 迷宫问题

 方法一:广搜

//BFS第二次编写
#include<stdio.h>
#include<string.h>

struct Node{
    int x,y;
    int pre;
}q[5*5 + 10];//使用数组创建的队列,出栈的时候不会真正的删除元素

int map[5][5];//输入矩阵,判断是否可达
int vis[5][5];//判断是否已经访问

//维护队列的指针,并且相当于完成初始化,直接存放第一个元素
//出队和入队千万不要忘记这两个指针的维护
int qhead = 0;//指向第一个元素
int qtail = 1;//指向最后一个元素的下一个元素

int X[4] = {1,-1,0,0};
int Y[4] = {0,0,-1,1};

int test(int x,int y){
    if(x<0 || x>=5 || y<0 || y>=5) return 0;
    if(map[x][y] == 1) return 0;
    if(vis[x][y] == 1) return 0;

    return 1;
}

void BFS(){
    //第一个节点入队
    q[qhead].x = 0;
    q[qhead].y = 0;
    q[qhead].pre = -1;
    vis[0][0] = 1;

    while(qhead<qtail){
        Node temp_head = q[qhead];//访问队首元素
        //qhead++;此处编写错误,会影响下面的q[qtail].pre = head;
        if(temp_head.x == 4 &&temp_head.y == 4)
            return;
        for(int i = 0;i<4;i++){
            int newX = temp_head.x + X[i];
            int newY = temp_head.y + Y[i];
            if(test(newX,newY)){
                //入队
                q[qtail].x = newX;
                q[qtail].y = newY;
                q[qtail].pre = qhead;
                vis[newX][newY] = 1;
                qtail++;
            }
        }
        qhead++;//出队,注意只有这个位置正确
    }
}
void print(int head){
    if(head == 0)
        printf("(0, 0)\n");
    else{
        if(q[head].pre != -1){
            print(q[head].pre);
            printf("(%d, %d)\n",q[head].x,q[head].y);
        }
    }
}
int main(){
    int i,j;
    for(i = 0;i<5;i++){
        for(j = 0;j<5;j++){
            scanf("%d",&map[i][j]);//输入数据
        }
    }
    BFS();
    print(qhead);
    memset(vis,0,sizeof(vis));//初始化vis数组
    return 0;
}

方法二:广搜

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<queue> 
using namespace std;
//定义结构体Step,用于记录当前点的坐标和步数
struct Step{
	int x,y;
	int steps;
};
//其中book表示这个点是否已经被访问过,初始化为
int a[5][5],book[5][5]={0};
//定义Next数组,表示每一步可以向上、下、左、右走的方向
int Next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
queue<Step> q;
Step pre[5][5];
void print(int x,int y){
	if(x==0&&y==0){
		printf("(0, 0)\n");
		return;
	}
	print(pre[x][y].x,pre[x][y].y);
	printf("(%d, %d)\n",x,y);
	return;
}

void bfs(){
	Step nd;
	nd.x=0,nd.y=0,nd.steps=0;
	book[0][0]=1;
	q.push(nd);
	while(!q.empty()){
		Step s=q.front();
		if(s.x==4&&s.y==4){
			print(4,4);
			break;
		}
		for(int i=0;i<4;i++){
			int nx=s.x+Next[i][0],ny=s.y+Next[i][1],step=s.steps+1;
			if((nx<=4&&nx>=0) && (ny<=4&&ny>=0) && book[nx][ny]==0 && a[nx][ny]==0){
				Step p; 
				p.x=nx,p.y=ny,p.steps=step;
				book[nx][ny] = 1; 
				pre[nx][ny].x = s.x,pre[nx][ny].y = s.y;
				q.push(p);
				}
		
		}
		q.pop();
	}
}

int main(void)
{
	for(int i=0;i<5;i++){
		for(int j=0;j<5;j++){
			cin>>a[i][j];
		}
	}
	bfs();
	return 0;
}

方法三:深搜

//http://bailian.openjudge.cn/practice/4127/
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;

const int INF = 100000000;

struct Node//DFS中存放的节点{
    int x,y;
    Node(int xx,int yy):x(xx),y(yy){}
};

int vis[5][5];
int map[5][5];

int X[4] = {1,-1,0,0};//方向
int Y[4] = {0,0,1,-1};

int test(int x,int y)//是否越界{
    if(x<0 || x>=5 || y<0 || y>=5)
        return 0;
    if(map[x][y] == 1)
        return 0;
    if(vis[x][y] == 1)
        return 0;
    return 1;
}

int min_dis = INF;//遍历所有的路径,找到最短路径
vector<Node> temp,path;//临时路径,最后的路径
void DFS(int x,int y){
    if(x == 4 && y == 4)//判断是否到达终点(4,4)
    {
        temp.push_back(Node(x,y));
        vis[x][y] = 1;

        if(temp.size() < min_dis)//更新最小距离,保存路径
        {
            min_dis = temp.size();
            path = temp;
        }

        temp.pop_back();
        vis[x][y] = 0;
        return ;//这行代码千万不要忘记
    }

    Node u = Node(x,y);//当前访问的节点u

    temp.push_back(u);//将该节点入栈
    vis[x][y] = 1;//访问

    for(int i = 0;i<4;i++)//访问其相邻节点
    {
        int newX = u.x + X[i];
        int newY = u.y + Y[i];
        if(test(newX,newY))
            DFS(newX,newY);
    }

    /*
    可以这样理解,在节点u访问完所有路径之后到达不了最终的节点
    */
    temp.pop_back();
    vis[x][y] = 0;
}

void print(){
    for(int i = 0;i<path.size();i++)
        printf("(%d, %d)\n",path[i].x,path[i].y);
}

int main(){
    int i,j;
    for(i = 0;i<5;i++)//输入数据
        for(j = 0;j<5;j++)
            scanf("%d",&map[i][j]);

    memset(vis,0,sizeof(vis));//初始化vis数组

    DFS(0,0);
    print();

    return 0;
}

B Anagram

方法一:深搜

#include<iostream>
#include<algorithm>
#include<cstring>
#include<set> 

using namespace std;
char a[13],b[13];
bool visited[13];
set<string> st;

bool cmp(char a,char b){
    double front,behind;
    if(a>='A'&&a<='Z')  front = (double)a+31.5;
    else  front = (double)a;
    if(b>='A'&& b<='Z')  behind = (double)b+31.5;
    else  behind = (double)b;
    return front<behind;
}
void dfs(int x,int len)
{
	if(x>=len)
	{
		st.insert(b);
	}
	else
	{
		for(int i=0;i<len;i++)
		{
			if(visited[i]) continue;
			else
			{
				b[x] = a[i];
				visited[i] = true;
				dfs(x+1,len);
				visited[i] = false;
			}
		}
	}
}
void Print(set<string> &a)
{
	set<string>::iterator it;
	for(it=a.begin();it!=a.end();it++)
	{
		cout<<*it<<endl;
	}
}
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a;
		int len = strlen(a);
		sort(a,a+len,cmp);
		dfs(0,len);
		
		Print(st);
		st.clear();
	}
	
	return 0;
}

方法二:全排列

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
using namespace std;

char s[5000];

bool cmp(char a,char b){
    double front,behind;
    if(a>='A'&&a<='Z')  front = (double)a+31.5;
    else  front = (double)a;
    if(b>='A'&& b<='Z')  behind = (double)b+31.5;
    else  behind = (double)b;
    return front<behind;
}
int main(){
    int count;
    cin>>count;

    while(count--){
        cin>>s;
        sort(s,s+strlen(s),cmp);

        do{
            cout<<s<<endl;
        }while(next_permutation(s,s+strlen(s),cmp));
    }

    return 0;
}

1164:The Castle

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;

const int N=101;
int cascle[N][N],vis[N][N];
int area,ans,num; 

void dfs(int i,int j){
	if(vis[i][j])						//标记过,则返回 
		return;
	vis[i][j]=1;						//标记 
	area++;
	if((cascle[i][j]&1)==0)
		dfs(i,j-1);						//向西 
	if((cascle[i][j]&2)==0)				 
		dfs(i-1,j);						//向北 
	if((cascle[i][j]&4)==0)
		dfs(i,j+1);						//向东 
	if((cascle[i][j]&8)==0)
		dfs(i+1,j);						//向南 
}

int main(){
	int m,n;
	cin>>m>>n;
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
			scanf("%d",&cascle[i][j]);
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++){
			if(vis[i][j])
				continue;
			num++;
			area=0;						
			dfs(i,j);
			ans=max(area,ans);
		}
	cout<<num<<endl<<ans;
}

在这段代码中,墙的信息用一个四位的二进制数表示。其中,每一位代表一面墙的存在与否。例如,二进制数的最低位代表西墙,次低位代表北墙,依次类推。

如果两个方块相邻且没有中间的墙隔开,那么它们之间就是相通的。因此,可以使用位运算来判断两个方块是否相通。

具体地说,根据题目中给出的墙的编码规则,得到如下对应关系:
- 方块的西墙:对应二进制数的最低位
- 方块的北墙:对应二进制数的次低位
- 方块的东墙:对应二进制数的次高位
- 方块的南墙:对应二进制数的最高位

如果方块的某一面墙存在,那么对应位的值为1;如果不存在,对应位的值为0。

所以,如果方块(i, j)与相邻方块相通,根据相邻方块在(i, j)的位置关系,二进制数的对应位与运算的结果为0。这是因为如果两个方块相通,对应位的墙要么都存在(为1),要么都不存在(为0),才能保证相通。

例如,如果方块(i, j)与西边的方块相通,则方块(i, j)的西墙不存在,对应的二进制数的最低位为0。因此,方块(i, j)的墙的信息与1进行与运算的结果为0。

所以,在这段代码中,通过对方块的墙的信息与1, 2, 4, 8进行与运算,如果结果为0,则说明该方块与对应的相邻方块相通。

#include<iostream>
using namespace std;

int a[100][100],vis[100][100];
int Size,res,num; 
int m,n;
int sum;

void dfs(int i,int j){
	if(sum>=m*n) return;
	
	if(vis[i][j]) return;
	
	sum++;
	
	vis[i][j]=1;
	Size++;
	if((a[i][j]&1)==0) dfs(i,j-1);
	if((a[i][j]&2)==0) dfs(i-1,j);
	if((a[i][j]&4)==0) dfs(i,j+1);
	if((a[i][j]&8)==0) dfs(i+1,j);
}

int main(){

	cin>>m>>n;
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
			scanf("%d",&a[i][j]);
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++){
			if(vis[i][j])
				continue;
			num++;
			Size=0;						
			dfs(i,j);
			res=max(Size,res);
		}
	cout<<num<<endl<<res;
}

1562:Oil Deposits

//http://bailian.openjudge.cn/practice/1562
#include<iostream>
using namespace std;
char map[101][101];
int result;
int n,m;
int move[8][2]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
//深度搜索
void dfs(int x,int y){
    int a,b;
    map[x][y] = '*'; //访问过的都由@改为*,剪枝
    for(int i=0;i<8;i++){
       a=x+move[i][0];
       b=y+move[i][1];
       if(a>=0&&a<n&&b>=0&&b<m&&map[a][b]=='@'){
           dfs(a,b);
       }
    }
}
int main(){
   while(cin>>n>>m&&n||m){
        int i,j;
        //初始化
        result=0;
        for(i=0;i<n;i++){
          cin>>map[i];
        }
        for(i=0;i<n;i++){
            for(j=0;j<m;j++){
                if(map[i][j]=='@'){
                    dfs(i,j);
                    result++;
                }
 
            }
        }
        //打印结果
        printf("%d\n",result);
 
   }
   return 0;
}

1565:Skew Binary

//http://bailian.openjudge.cn/practice/1565
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
long long res;
long long skew(char x[]){
	int len=strlen(x);
//	cout<<len<<endl;
	int mi=len;
	res = 0;
	for(int i=0;i<len;i++){
		res+=(x[i]-'0')*(pow(2,mi)-1);
//		cout<<pow(2,mi)-1<<endl;
		mi--;
	}
	return res;
}
int main(){
	char n[10000];
	while(cin>>n&&strcmp(n,"0")){
		res=skew(n);
		cout<<res;
	}
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值