dfs ,bfs 思路+代码+总结

01自然数的拆分问题

Description

任何一个大于 11 的自然数 nn,总可以拆分成若干个小于 nn 的自然数之和。现在给你一个自然数 nn,要求你求出 nn 的拆分成一些数字的和。每个拆分后的序列中的数字从小到大排序。然后你需要输出这些序列,其中字典序小的序列需要优先输出。

Input

输入:待拆分的自然数 nn。

Output

输出:若干数的加法式子

#include<bits/stdc++.h>
using namespace std;
int n;
int a[20];
void dfs(int x,int s){
	if(s==0){
		for(int i=0;i<x-1;i++){
			cout<<a[i]<<"+";
		}cout<<a[x-1]<<endl;
		return ;
	}
	for(int i=1;i<=s;i++){
		if(i<a[x-1]){
			continue;
		}
		a[x]=i;
		dfs(x+1,s-i);
		a[x]=0;
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=n/2;i++){
		a[0]=i;
		dfs(1,n-i);
	}
	return 0;
}

思路:

#include<bits/stdc++.h>
using namespace std;
int n;
int a[10];//放答案(加数) 
void dfs(int x,int s){
    if(s==0){
        for(int i=0;i<x-1;i++){
            cout<<a[i]<<'+';
        }cout<<a[x-1]<<endl;
        return;
    }//减到0停止 
    for(int i=1;i<=s;i++){
        if(i<a[x-1]){
            continue;
        }//与上一个加数比较 
        a[x]=i;//放进去 
        dfs(x+1,s-i);//找下一个加数 
        a[x]=0;//还原 
    }
}
int main(){
    cin>>n;
    for(int i=1;i<=n/2;i++){
        a[0]=i;//第一个加数,枚举(加数<=n/2) 
        dfs(1,n-i);//深搜 
    }

 02填涂颜色

Description

由数字 00 组成的方阵中,有一任意形状的由数字 11 构成的闭合圈。现要求把闭合圈内的所有空间都填写成 22。例如:6\times 66×6 的方阵(n=6n=6),涂色前和涂色后的方阵如下:

如果从某个 00 出发,只向上下左右 44 个方向移动且仅经过其他 00 的情况下,无法到达方阵的边界,就认为这个 00 在闭合圈内。闭合圈不一定是环形的,可以是任意形状,但保证闭合圈内的 00 是连通的(两两之间可以相互到达)。

0 0 0 0 0 0
0 0 0 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 1 0 1
1 1 1 1 1 1

Copy

Plain text

0 0 0 0 0 0
0 0 0 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 1 2 1
1 1 1 1 1 1

Copy

Plain text

Input

每组测试数据第一行一个整数 n(1 \le n \le 30)n(1≤n≤30)。

接下来 nn 行,由 00 和 11 组成的 n \times nn×n 的方阵。

方阵内只有一个闭合圈,圈内至少有一个 00。

Output

已经填好数字 22 的完整方阵。

思路:

#include<bits/stdc++.h>
using namespace std;
int n;
const int N=35;
int a[N][N];
int b[N][N];//将是1处的点当做走过,将里面的0围起来,b数组标记走过的点 
void dfs(int x,int y){
    if(x<0||x>n+1||y>n+1||y<0||b[x][y]==1){
        return;
    }//走过或者越界 截断 (向外补一圈) 
    if(a[x][y]==0){
        b[x][y]=1;
    }
    dfs(x+1,y);
    dfs(x-1,y);
    dfs(x,y-1);
    dfs(x,y+1);//四个方向 
}
int main(){
    cin>>n;
    memset(b,0,sizeof(b));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin>>a[i][j];
            if(a[i][j]==1){
                b[i][j]=1;
            }
        }
    }
    dfs(0,0);//从(0,0)开始深搜 
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(b[i][j]==0){
                cout<<2<<" ";//没走过的就是被围起来的 
            }
            else{
                cout<<a[i][j]<<" ";
            }
        }cout<<endl;
    }
    
}

#include<bits/stdc++.h>
using namespace std;
int n;
int a[35][35];
int st[35][35];
void dfs(int x,int y){
	if(x<0||x>n+1||y<0||y>n+1||st[x][y]==1){
		return;
	}
	st[x][y]=1;
	dfs(x+1,y);
	dfs(x-1,y);
	dfs(x,y+1);
	dfs(x,y-1);
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>a[i][j];
			if(a[i][j]==1){
				st[i][j]=1;
			}
		}
	}
	dfs(0,0);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(st[i][j]==0){
				cout<<2<<" ";
			}
			else{
				cout<<a[i][j]<<" ";
			}
		}cout<<endl;
	}
	return 0;

 

03显示图像

 

Description

古老的显示屏是由 N \times MN×M 个像素(Pixel)点组成的。一个像素点的位置是根据所在行数和列数决定的。例如 P(2,1)P(2,1) 表示第 22 行第 11 列的像素点。那时候,屏幕只能显示黑与白两种颜色,人们用二进制 00 和 11 来表示。00 表示黑色,11 表示白色。当计算机发出一个指令:P(x,y)=1P(x,y)=1,则屏幕上的第 xx 行第 yy 列的阴极射线管就开始工作,使该像素点显示白色,若 P(x,y)=0P(x,y)=0,则对应位置的阴极射线管不工作,像素点保持黑色。在某一单位时刻,计算机以 N \times MN×M 二维 0101 矩阵的方式发出显示整个屏幕图像的命令。

例如,屏幕是由 3 \times 43×4 的像素点组成,在某单位时刻,计算机发出如下命令:

\begin{pmatrix} 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 1 \\ 0 & 1 & 1 & 0 \\ \end{pmatrix}​000​001​011​110​​

对应屏幕显示应为:

假设放大后,一个格子表示一个像素点。

由于未知的原因,显示黑色的像素点总是受显示白色的像素点的影响——可能是阴极射线管工作的作用。并且,距离越近,影响越大。这里的距离定义如下:

设有像素点 P_1(x_1,y_1)P1​(x1​,y1​) 和像素点 P_2(x_2,y_2)P2​(x2​,y2​),则它们之间的距离 D(P_1,P_2)=|x_1-x_2|+|y_1-y_2|D(P1​,P2​)=∣x1​−x2​∣+∣y1​−y2​∣。

在某一时刻,计算机发出显示命令后,科学家们期望知道,每个像素点和其最近的显示白色的像素点之间的最短距离是多少——科学家们保证屏幕上至少有一个显示白色的像素点。

上面的例子中,像素 P(1,1)P(1,1) 与最近的白色像素点之间的距离为 33,而像素 P(3,2)P(3,2) 本身显示白色,所以最短距离为 00。

Input

第一行有两个数字,NN 和 M\ (1 \le N,M \le 182)M (1≤N,M≤182),表示屏幕的规格。

以下 NN 行,每行 MM 个数字,00 或 11。为计算机发出的显示命令。

Output

输出文件有 NN 行,每行 MM 个数字,中间用 11 个空格分开。第 ii 行第 jj 列的数字表示距像素点 P(i,j)P(i,j) 最近的白色像素点的最短距离。

思路:

#include<bits/stdc++.h>
using namespace std;
int n,m;
const int N=200;
char a[N][N];
int b[N][N];
bool v[N][N];
struct node{
    int x,y,d;
};
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
queue<node>q;
void bfs(){
    node next,now;
    while(!q.empty()){
    now=q.front();//头 
    int x=now.x,y=now.y,d=now.d;
    q.pop();//拿出来 
    b[x][y]=d;//最短距离就是d 
    for(int i=0;i<4;i++){
        int sx=x+dx[i];
        int sy=y+dy[i];//往四面跑 
        if(sx>=1&&sx<=n&&sy>=1&&sy<=m&&a[sx][sy]=='0'&&v[sx][sy]==0){//没有越界 
            v[sx][sy]=1;//标记 
            next.x=sx;
            next.y=sy;
            next.d=d+1;//多了一步+1 
            q.push(next);//放进下一个 
        }
    }
}
}
int main(){
    node c;
    cin>>n>>m;
    memset(v,0,sizeof(v));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
            if(a[i][j]=='1'){//注意是==‘1’
                c.x=i;c.y=j;c.d=0;
                q.push(c);//放进去 
                v[i][j]=1;//跑过 
            }//从1出发 
            b[i][j]=10000;
        }
    }
    bfs();//开始广搜 
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cout<<b[i][j]<<" ";
        }cout<<endl;
    }//输出答案 
}

#include<bits/stdc++.h>
using namespace std;
int n,m;
const int N=200;
char a[N][N];
int b[N][N];
bool v[N][N];
struct node{
int x,y,d;	
};
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
queue<node>q;
void bfs(){
	node net,now;
	while(!q.empty()){
		now=q.front();
		q.pop();
		int x=now.x,y=now.y,d=now.d;
		b[x][y]=d;
		for(int i=0;i<4;i++){
		int nx=x+dx[i],ny=y+dy[i];
		if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&v[nx][ny]==0&&a[nx][ny]=='0'){
			v[nx][ny]=1;
			net.x=nx;
			net.y=ny;
			net.d=d+1;
			q.push(net);
		}	
		}
	}
}
int main(){
	node pp;
	memset(v,0,sizeof v);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
			
			if(a[i][j]=='1'){
				pp.x=i;pp.y=j;
				pp.d=0;
				v[i][j]=1;
				q.push(pp);
			}
			b[i][j]=100000;
		}
	}
	bfs();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cout<<b[i][j]<<" ";
		}
		cout<<endl;
	}
	return 0;
}

04 健康的荷斯坦奶牛

Description

农民 John 以拥有世界上最健康的奶牛为傲。他知道每种饲料中所包含的牛所需的最低的维他命量是多少。请你帮助农夫喂养他的牛,以保持它们的健康,使喂给牛的饲料的种数最少。

给出牛所需的最低的维他命量,输出喂给牛需要哪些种类的饲料,且所需的饲料剂量最少。

维他命量以整数表示,每种饲料最多只能对牛使用一次,数据保证存在解。

Input

第一行一个整数 vv,表示需要的维他命的种类数。
第二行 vv 个整数,表示牛每天需要的每种维他命的最小量。

第三行一个整数 gg,表示可用来喂牛的饲料的种数。
下面 gg 行,第 nn 行表示编号为 nn 饲料包含的各种维他命的量的多少。

Output

输出文件只有一行,包括牛必需的最小的饲料种数 pp;后面有 pp 个数,表示所选择的饲料编号(按从小到大排列)。

如果有多个解,输出饲料序号最小的(即字典序最小)

思路:

#include<bits/stdc++.h>
using namespace std;
int v,g;
int need[30];
int a[20][30];
bool visit[20];
int ans[20];
int len;
int minn=15;
int sum[20];
int anss[20];
bool right(int x){
    int f=0;
    memset(sum,0,sizeof(sum));
    for(int i=1;i<=v;i++){
        for(int j=1;j<=len;j++){
            sum[i]+=a[ans[j]][i];
        }
    }
    for(int i=1;i<=v;i++){
        if(sum[i]<need[i]){
            f=1;break;
        }
    }
    if(f==1){
        return false;
    }return true;
}
void dfs(int x){
    if(x>g||x>minn){
        return;
    }//越界的和比之前的最小的大的  截枝 
    if(right(len)){//符合need 
        if(len<minn){
            minn=len;
            for(int i=1;i<=len;i++){
                anss[i]=ans[i];
            }
        }return;
    }
    int start=ans[x];//从这种开始往下找 ,避免出现相同的答案 
    if(start==0){
        start=1;
    }
    for(int i=start;i<=g;i++){
        if(visit[i]==0){
            visit[i]=1;
        ans[x]=i;
        len++;
        dfs(x+1); //开始找下一种 
        ans[x]=0;//还原 
        len--;
        visit[i]=0;
        }
        
    }
}
int main(){
    cin>>v;
    memset(visit,0,sizeof(visit));
    for(int i=1;i<=v;i++){
        cin>>need[i];
    }
    cin>>g;
    for(int i=1;i<=g;i++){
        for(int j=1;j<=v;j++){
            cin>>a[i][j];
        }
    }
    dfs(1);//开始找第一种饲料 
    cout<<minn<<" ";
    for(int i=1;i<=minn;i++){
        cout<<anss[i]<<" ";
    }
}

#include<bits/stdc++.h>
using namespace std;
int v,g;
const int N=30;
int need[N];
int a[N][N];
bool st[N];
int sum[N];
int ans[N];
int minnn[N];
int minn=1000,len;
bool right(int l){
	memset(sum,0,sizeof(sum));
	for(int i=1;i<=l;i++){
			for(int j=1;j<=v;j++){
				sum[j]+=a[ans[i]][j];
			}
		}
		
	for(int i=1;i<=v;i++){
		if(sum[i]<need[i]){
			return false;
		}
	}
	return true;
}
void dfs(){
	if(len>g||len>minn){
		return;
	}
	if(right(len)){
		if(minn>len){
			minn=len;
			for(int i=1;i<=len;i++){
				minnn[i]=ans[i];
			}
		}return;
	}
	int start=ans[len];
	if(start==0){
		start=1;
	}
	for(int i=start;i<=g;i++){
		if(!st[i]){
			st[i]=1;
			len++;
			ans[len]=i;
			dfs();
			st[i]=0;
			ans[len]=0;
			len--;
		}
	}
}
int main(){
	memset(st,0,sizeof(st));
	cin>>v;
	for(int i=1;i<=v;i++){
		cin>>need[i];
	}
    cin>>g;
    for(int i=1;i<=g;i++){
    	for(int j=1;j<=v;j++){
    		cin>>a[i][j];	
		}
	}
	dfs();
	cout<<minn<<" ";
	for(int i=1;i<=minn;i++){
		cout<<minnn[i]<<" ";
	}
}

 

05GRZ-Ridges and Valleys

 给定一张地势图,求山峰和山谷的数量

思路:

#include<bits/stdc++.h>
using namespace std;
int n;
int ans1,ans2;
const int N=1005;
int a[N][N];
bool b[N][N];
int dx[8]={0,1,-1,0,1,1,-1,-1};
int dy[8]={1,0,0,-1,1,-1,1,-1};

int f1,f2;
void bfs(int x,int y){
    queue<pair<int, int> >q;
    q.push({x,y});//放进去 
    int h=a[x][y];//高度 
    while(!q.empty()){
    int sx=q.front().first;
    int sy=q.front().second;
    q.pop();//拿出来 
    for(int i=0;i<8;i++){//从八面找 
        int nx=sx+dx[i];
        int ny=sy+dy[i];
        if(nx>=1&&nx<=n&&ny>=1&&ny<=n){//没有越界 
            if(a[nx][ny]==h&&b[nx][ny]==0){//高度一样,且没有标记过 
            b[nx][ny]=1;//标记 
                q.push({nx,ny});//放进去 
            }
            if(a[nx][ny]<h){
                f1=1;//注意不用标记 
            }
            if(a[nx][ny]>h){
                f2=1;
            }
        }
    }
}
}
int main(){
    cin>>n;
    int f=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin>>a[i][j];
            if(a[i][j]!=a[1][1]){
                f=1;
            }
        }
    }
    if(f==0){
        cout<<1<<" "<<1<<endl;
        return 0;
    }//全都一样高 
     memset(b,0,sizeof(b));//全未标记过 
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(b[i][j]==0){//没有标记过的点,未知是不是山峰或山谷 
                b[i][j]=1;//标记 
                bfs(i,j);//搜 
                if(f1==1&&f2==0){
                    ans1++;
                }
                if(f1==0&&f2==1){
                    ans2++;
                }
                f1=0;f2=0;
            }
        }
    }
    cout<<ans1<<" "<<ans2<<endl;
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
int n;
const int N=1005;
int a[N][N];
bool b[N][N];
int i,j;
int f1,f2;
int ans1,ans2;
int dx[8]={0,1,0,-1,1,1,-1,-1};
int dy[8]={1,0,-1,0,1,-1,1,-1};
void dfs(int x,int y){
	b[x][y]=1;
	queue<int>x1,y1;
	x1.push(x);
	y1.push(y);
	while(!x1.empty()){
		int xs=x1.front();
		int ys=y1.front();
		x1.pop();y1.pop();
		for(int k=0;k<8;k++){
			int nx=xs+dx[k];
			int ny=ys+dy[k];
			if(nx>=1&&nx<=n&ny>=1&&ny<=n){
				if(a[nx][ny]==a[xs][ys]){
					if(b[nx][ny]==0){
						x1.push(nx);
						y1.push(ny);
						b[nx][ny]=1;
					}
				}
				if(a[nx][ny]<a[xs][ys]){
					f1=1;
				}
				if(a[nx][ny]>a[xs][ys]){
					f2=1;
				}
			}
		}
	}
	
}
int main(){
	cin>>n;
    int f=0;
    memset(b,0,sizeof(b));
	for(int q=1;q<=n;q++){
		for(int p=1;p<=n;p++){
			cin>>a[q][p];
			if(a[q][p]!=a[1][1]){
				f=1;
			}
		}
	}
	if(f==0){
		cout<<1<<" "<<1<<endl;
		return 0;
	}
	for(i=1;i<=n;i++){
		for(j=1;j<=n;j++){
			if(b[i][j]==0){
			
			dfs(i,j);
			if(f1==1&&f2==0){
				ans1++;
			}
			if(f1==0&&f2==1){
				ans2++;
			}
			f1=0;
			f2=0;
			}
		}
	}
	cout<<ans1<<" "<<ans2<<endl;
	
}

 06八皇后 Checker Challenge

 

Description

一个如下的 6 \times 66×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

上面的布局可以用序列 2\ 4\ 6\ 1\ 3\ 52 4 6 1 3 5 来描述,第 ii 个数字表示在第 ii 行的相应位置有一个棋子,如下:

行号 1\ 2\ 3\ 4\ 5\ 61 2 3 4 5 6

列号 2\ 4\ 6\ 1\ 3\ 52 4 6 1 3 5

这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 33 个解。最后一行是解的总个数。

Input

一行一个正整数 nn,表示棋盘是 n \times nn×n 大小的。

Output

前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

思路:

 #include<bits/stdc++.h>
using namespace std;
int n;
int m1[30],m2[30],m3[30];
int a[15];
void setvalue(int x,int y,int t){
    m1[y]=t;
    m2[x+y]=t;
    m3[x-y+n]=t;
}
int mark;//mark表示总的数量 
void bfs(int step){
    if(step>n){mark++;
    if(mark<=3){
    for(int i=1;i<=n;i++){
        cout<<a[i]<<" ";
    }cout<<endl;
       }return;
    }//如果>最后一行 输出 结束 
    
    for(int i=1;i<=n;i++){
        if(m1[i]||m2[i+step]||m3[step-i+n]){
            continue;
        }//被标记过不可用 
        a[step]=i;//a数组存此行用哪一列的格子 
        setvalue(step,i,1);//用,然后标记 
        bfs(step+1);//下一行 
        a[step]=0;
        setvalue(step,i,0);//还原 
    }
}
int main(){
    cin>>n;
    bfs(1);//从第一行开始 
    cout<<mark;
    return 0; 
}

 

#include<bits/stdc++.h>
using namespace std;
int n,m1[30],m2[30],m3[30],ans[15];
int mark;
void setvalue(int x,int y,int t){
	ans[x]=y;
	m1[y]=t;
	m2[x+y]=t;
	m3[x-y+n]=t;
}
void dfs(int step){
	if(step>n){mark++;
		if(mark<=3){
			for(int i=1;i<=n;i++){
				cout<<ans[i]<<" ";
			}
			cout<<endl;
		}
		return;
	}
	for(int j=1;j<=n;j++){
		if(m1[j]||m2[step+j]||m3[step-j+n]){
			continue;
		}
		
		setvalue(step,j,1);
		dfs(step+1);
		setvalue(step,j,0);
	}
}
int main(){
	cin>>n;
	dfs(1);
	cout<<mark;
	return 0;
}
Vivado2023是一款集成开发环境软件,用于设计和验证FPGA(现场可编程门阵列)和可编程逻辑器件。对于使用Vivado2023的用户来说,license是必不可少的。 Vivado2023的license是一种许可证,用于授权用户合法使用该软件。许可证分为多种类型,包括评估许可证、开发许可证和节点许可证等。每种许可证都有不同的使用条件和功能。 评估许可证是免费提供的,让用户可以在一段时间内试用Vivado2023的全部功能。用户可以使用这个许可证来了解软件的性能和特点,对于初学者和小规模项目来说是一个很好的选择。但是,使用评估许可证的用户在使用期限过后需要购买正式的许可证才能继续使用软件。 开发许可证是付费的,可以永久使用Vivado2023的全部功能。这种许可证适用于需要长期使用Vivado2023进行开发的用户,通常是专业的FPGA设计师或工程师。购买开发许可证可以享受Vivado2023的技术支持和更新服务,确保软件始终保持最新的版本和功能。 节点许可证是用于多设备或分布式设计的许可证,可以在多个计算机上安装Vivado2023,并共享使用。节点许可证适用于大规模项目或需要多个处理节点进行设计的用户,可以提高工作效率和资源利用率。 总之,Vivado2023 license是用户在使用Vivado2023时必须考虑的问题。用户可以根据自己的需求选择合适的许可证类型,以便获取最佳的软件使用体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值