目录
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;
}
}