超简单搜索

搜索

1.dfs(排列组合问题,列出所有的情况)

1.1线性

1.1.1全排列

/*全排列板子 */
#include<stdio.h>
int a[10],n,hash[10]={0};
void dfs(int step)
{
	if(step==n+1)
	{
		for(int i=1;i<=n;i++) printf("%d ",a[i]);
		printf("\n");
		return;
	}
	for(int i=1;i<=9;i++)
	{
		if(hash[i]==0)
		{
			a[step]=i;
			hash[i]=1;
			dfs(step+1);
			hash[i]=0;//只有线性才会用这个,非线性用反而错了 
		}
	}
	return;
}
int main()
{
	scanf("%d",&n);
	dfs(1);//不需要判断起始点是否存在的均从1开始
	return 0;
}

组合问题板子

题目描述
排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且r < = n),我们可以简单地将n个元素理解为自然数12,…,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 < 211 < = r < = n )。

输出
所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,所有的组合也按字典顺序。
#include<iostream>
#include<stdio.h>
using namespace std;
int r,n;
int jilu[100]={0};
bool hashtable[100]={false};
bool hashtable2[100]={false};
void dfs(int step)
{
    if(step==r+1)
    {
        for(int i=1;i<=r;i++)
        {
            printf("%d ",jilu[i]);        
        }
		printf("\n");
		return;
    }
    for(int i=jilu[step-1];i<=n;i++)
    {
        if(hashtable[i]==false)
        {
            hashtable[i]=true;
            jilu[step]=i;
            dfs(step+1);
            hashtable[i]=false;
        }
    }
}
int main()
{
    scanf("%d %d",&n,&r);
    jilu[0]=1;
    dfs(1);
    return 0;
}

1.1.2排列组合通项

/*
A - 棋盘问题
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
Input
输入含有多组测试数据。
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
Output
对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。
Sample Input
2 1
#.
.#
4 4
...#
..#.
.#..
#...
-1 -1
Sample Output
2
1
*/ 
#include<iostream>
#include<stdio.h>
using namespace std;
const int maxn=1010;
int n,k;
char jilu[maxn][maxn];
bool hashtable[maxn]={false};
int c=0;
void dfs(int step,int xia)//双限制的属性 
{
	if(xia==k+1)//此处+1别给忘了 
	{
		c++;
		return;
	}
	if(step==n+1) return;//这也是,而且是双限制(也就是说我写出了排列组合的通式) 
	int flag=0;
	for(int i=1;i<=n;i++)
	{
		if(jilu[step][i]=='#'&&hashtable[i]==false)
		{
			hashtable[i]=true;
			dfs(step+1,xia+1);
			hashtable[i]=false;
		}
	}
	dfs(step+1,xia);//此处与全排列的差异 
} 
int main()
{
	while(1)
	{
		scanf("%d %d",&n,&k);
		getchar();//数字转换字符串的时候要加 
		if(n==-1&&k==-1) break;
		else
		{
			for(int i=1;i<=n;i++)
			{
				for(int j=1;j<=n;j++) jilu[i][j]=getchar();
				getchar();
			}
		}
		dfs(1,1);
		printf("%d\n",c);
		c=0;
	}
	return 0;
}

1.2非线性
1.2.1.地图炮(相当于板子吧)

/*
有一天,小哈一个去玩迷宫。但是方向感很不好的小哈很快就迷路了。小哼得知后便立即去解救无助的小哈。小哼当然是有备而来,已经弄清楚了迷宫地图,现在小哼要以最快速度去解救小哈。问题就此开始了……
  迷宫由n行m列的单元格组成,每个单元格要么是空地,要么是障碍物。你的任务是帮助小哼找到一条从迷宫的起点到小哈所在位置的最短路径,注意障碍物是不能走的,当然也不能走到迷宫之外。n和m都小于等于100。
输入格式:

第一行有两个数N M。N表示迷宫的行,M表示迷宫的列。接来下来N行M列为迷宫,0表示空地,1表示障碍物。最后一行4个数,前两个数为迷宫入口的x和y坐标。后两个为小哈的x和y坐标。
输出格式:

一个整数表示小哼到小哈的最短步数。如果不能解救小哈则输出No Way!
输入:
5 4
0 0 1 0
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1
1 1 4 3
输出:
7
样例 2 :

输入:
3 3
1 1 1 
0 1 0  
0 1 0 
2 1 3 3
输出:
No Way!
*/
/*
void dfs(int step)
{
	判断边界;
	for(i=1;i<=n;i++)//尝试每一种可能
	{
		继续下一步 dfs(step+1);
	}
	返回;
}
*/
#include<stdio.h>
int n,m,p,q,min=9999999;
int a[51][51],hash[51][51]={0};
void dfs(int x,int y,int step)//迭代时一般不用赋值可以直接用函数实现 
{
	int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
	if(x==p&&y==q)
	{
		if(step<min) min=step;
		return;
	}
	for(int k=0;k<=3;k++)
	{
		int tx=x+next[k][0];
		int ty=y+next[k][1];
		if(tx<1||tx>n||ty<1||ty>m) continue;
		if(hash[tx][ty]==0&&a[tx][ty]==0) 
		{
			hash[tx][ty]=1;
			dfs(tx,ty,step+1);
			//这里与线性不同 
		}
	}
	return;
}
int main()
{
	int startx,starty;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++) scanf("%d",&a[i][j]);
	}
	scanf("%d %d %d %d",&startx,&starty,&p,&q);
	hash[startx][starty]=1;
	dfs(startx,starty,0);//从0开始,与一维的有所区别(也就是说起点即终点)用来判断 
	printf("%d",min);
	return 0;
}

1.2.2再解炸弹人(初始化问题,数组越界问题)

/*
输入样例:

13 13 3 3
#############
#GG.GGG#GGG.#
###.#G#G#G#G#
#.......#..G#
#G#.###.#G#G#
#GG.GGG.#.GG#
#G#.#G#.#.#.#
##G...G.....#
#G#.#G###.#G#
#...G#GGG.GG#
#G#.#G#G#.#G#
#GG.GGG#G.GG#
#############

输出样例:

炸弹放置在(8,12),消灭敌人最多为10
*/
#include<stdio.h>
#include<algorithm>
using namespace std;
int n,m;
int startx,starty;
struct node
{
	int max1;
	int x,y;
}Node;
bool hash[100][100]={false};
char jilu[100][100];
int heng[5]={0,0,0,1,-1};
int shu[5]={0,1,-1,0,0};
bool test(int x,int y)
{
	if(x<1||x>n||y<1||y>m) return false;//这个一定要在前,否则可能数组越界 
	if(hash[x][y]==true) return false;
	if(jilu[x][y]=='#'||jilu[x][y]=='G') return false;//此处也不能等于G 
	return true;
}
void xiaomie(int x,int y)
{
	int temp=0;
	for(int i=1;i<=4;i++)
	{
		int tx=x+heng[i];
		int ty=y+shu[i];
		while((tx>=1&&tx<=n&&ty>=1&&ty<=m)&&jilu[tx][ty]!='#')//防止数组越界,所以边界条件要在前面 
		{
			if(jilu[tx][ty]=='G') temp++; 
			tx+=heng[i];
			ty+=shu[i]; 
		}
		
	}
	Node.max1=max(Node.max1,temp);
	if(Node.max1==temp)
	{
		Node.x=x;
		Node.y=y;
	}
}
void dfs(int x,int y,int step)
{
	for(int i=1;i<=4;i++)
	{
		int sx=x+heng[i];
		int sy=y+shu[i];
		if(test(sx,sy))
		{
			xiaomie(sx,sy);
			hash[sx][sy]=true;
			dfs(sx,sy,step+1);
		}
	}
	return;
}
int main()
{
	Node.max1=-1;
	scanf("%d %d %d %d",&n,&m,&startx,&starty);
	startx+=1;
	starty+=1;
	getchar();
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++) scanf("%c",&jilu[i][j]);
		getchar();
	}
	xiaomie(startx,starty);//每个都要初始化 
	hash[startx][starty]=true;//每个都要初始化 
	dfs(startx,starty,0);
	printf("%d %d %d",Node.x,Node.y,Node.max1);
	return 0;
}

1.2.3水管工游戏(输出路径用vector)

/*5 4
5 3 5 3
1 5 3 0
2 3 5 1
6 1 1 5
1 5 5 4
水管工游戏是指如下图中的矩阵中,一共有两种管道,一个是直的,一个是弯的,所有管道都可以自由旋转,最终就是要连通入水口可出水口。其中的树为障碍物。
*/
#include<stdio.h>//不用循环是因为不好有多种情况 
#include<algorithm>
#include<vector>
using namespace std;
struct node
{
	int x;
	int y;
}Node;
int n,m;
bool hash[100][100]={false};
int jilu[100][100];
vector<node> s;
int flag=0;//没return就是impossible 
bool test(int x,int y)
{
	if(x<1||x>n||y<1||y>m) return false;
	if(hash[x][y]==true) return false;
	if(jilu[x][y]==0) return false;
	return true;
}
void dfs(int x,int y,int front)//x为竖行y为横行一定要注意 
{
	if(x==n&&y==m+1)
	{
		flag=1;
		for(int i=0;i<s.size();i++) printf("(%d,%d) ",s[i].x,s[i].y);
	}
	node temp;
	temp.x=x;
	temp.y=y;
	s.push_back(temp);
	if(!test(x,y))
	{
		s.pop_back();//此处加最为合适 
		return;
	}
	hash[x][y]=1;
	if(jilu[x][y]<=6&&jilu[x][y]>=5)
	{
		if(front==1) dfs(x,y+1,3);
		if(front==2) dfs(x+1,y,2);
		if(front==3) dfs(x,y-1,1);
		if(front==4) dfs(x-1,y,4);
	}
	else
	{
		if(front==1)
		{
			dfs(x+1,y,2);
			dfs(x-1,y,4);
		}
		if(front==2)
		{
			dfs(x,y+1,1);
			dfs(x,y-1,3);
		}
		if(front==3)
		{
			dfs(x-1,y,4);
			dfs(x+1,y,2);
		}
		if(front==4)
		{
			dfs(x,y+1,1);
			dfs(x,y-1,3);
		}
	}
}
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++) scanf("%d",&jilu[i][j]);
	} 
	dfs(1,1,1);
	if(flag==0) printf("Impossible");
	return 0;
}

2.bfs(最短路问题)

2.1广搜板子(迷宫问题)

//广搜基本写法 ,迷宫问题 
/*5 5
.....
.*.*.
.*S*.
.***.
...T*
2 2 4 3*/
/*
void bfs(起点start)//book为标记数组,1表示已经访问
{
	Queue q;
	q = 起点start;
	while(q非空)
	{
		q首元素x出队;
		所有与x相邻且未被访问的点入队;
		book[x] = 1;
	}
}
*/
#include<stdio.h>
#include<iostream>
#include<queue>//此处用队列 
using namespace std;
const int maxn=100;
int n,m;
char cun[maxn][maxn];
bool hash[maxn][maxn]={false};//是入没入过队列,而不是有没有走过(节省大量时间,因为有可能入过队列但还没来得及执行) 
struct node
{
	int x,y;
	int step;
}s,t,Node;//Node为临时节点 
int heng[4]={0,0,1,-1};
int shu[4]={1,-1,0,0};
bool test(int x,int y)
{
	if(x<1||x>n||y<1||y>m) return false;//边界 
	if(cun[x][y]=='*') return false;//障碍物 
	if(hash[x][y]==true) return false;
	return true;
}
int bfs()
{
	queue<node> q;//此处定义队列,队列传进去仅仅只是副本,对副本的修改修改不了原元素,对原元素的修改也修改不了副本 
	q.push(s);
	while(!q.empty())
	{
		node temp=q.front();
		q.pop();
		if(temp.x==t.x&&temp.y==t.y) return  temp.step;
		for(int i=0;i<=3;i++)
		{
			int tx=temp.x+heng[i];
			int ty=temp.y+shu[i];
			if(test(tx,ty))
			{
				Node.x=tx;
				Node.y=ty;
				Node.step=temp.step+1;
				q.push(Node);
				hash[tx][ty]=true;//意思是已入队 
			}
		}
	}
	return -1;
}
int main()
{
	scanf("%d%d",&n,&m);
	getchar();
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++) cun[i][j]=getchar();
		getchar();
	}
	scanf("%d%d%d%d",&s.x,&s.y,&t.x,&t.y);
	s.x+=1;
	s.y+=1;
	t.x+=1;
	t.y+=1;
	s.step=0;
	printf("%d\n",bfs());
	return 0;
} 

//讲道理有时候输出格式都卡得这么严
/*
7-9 Killing Cubes
The Great God Xiao is trapped in a 3D dungeon! The dungeon is composed of unit cubes which may or may not be dangerous. It takes one minute to move one unit north, south, east, west, up or down. Long Xiao cannot move diagonally and the cubes are made up of special metal which can't be passed through.

Now, The Great God Qin Yi Ran, the ACM teammate of God Xiao, need to make a plan for the Great Long Xiao, and when he escape successfully, he will wear a suit of women to thank him!

Can he escape? If yes, how long will it take?

输入格式:
You will be given a number of cases in the input.

Each case starts with a line containing L, R, C (1 <= L, R, C <= 30). L, R and C mean the level, row and column size of a dungeons.

Then there will follow L blocks of R lines each containing C characters. Each character describes one cell of the dungeon. A cell full of rock is indicated by a '#' and empty cells are represented by a '.'. God Xiao’s starting position is indicated by 'S' and the exit by the letter 'E'. There's a single blank line after each level. Input is terminated by three zeroes for L, R and C.

输出格式:
Each maze generates one line of output. If it is possible to reach the exit, print a line of the shortest minutes needed to escape. If it is not possible to escape, print the line "No dress to appreciate!"

输入样例:
在这里给出一组输入。例如:

3 4 5
S....
.###.
.##..
###.#

#####
#####
##.##
##...

#####
#####
#.###
####E

1 3 3
S##
#E#
###

0 0 0
输出样例:
在这里给出相应的输出。例如:

11
No dress to appreciate!
*/ 
#include<iostream>
#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
int L,R,C;
int L1[9]={0,1,-1,0,0,0,0};
int R1[9]={0,0,0,1,-1,0,0};
int C1[9]={0,0,0,0,0,1,-1};
char tu[32][32][32];
bool book[32][32][32]={false};
struct node
{
	int i;
	int j;
	int k;
	int step;
};
inline bool check(int a,int b,int c)
{
	if(a>=L+1||a<=0||b>=R+1||b<=0||c>=C+1||c<=0) return false;
	if(book[a][b][c]==true) return false;
	if(tu[a][b][c]=='#') return false;
	return true;
}
inline int bfs(node qidian)
{
	memset(book,0,sizeof(book));
	queue<node> q;
	q.push((node){qidian.i,qidian.j,qidian.k,qidian.step});
	while(!q.empty())
	{
		node temp2=q.front();
		q.pop();
		for(int i=1;i<=6;i++)
		{
			node tx;
			tx.i=temp2.i+L1[i];
			tx.j=temp2.j+R1[i];
			tx.k=temp2.k+C1[i];
			tx.step=temp2.step;
			if(tx.i >= 1 && tx.i <= L && tx.j >= 1 && tx.k >= 1 && tx.j <= R && tx.k <= C && book[tx.i][tx.j][tx.k] == 0 && (tu[tx.i][tx.j][tx.k] == '.'||tu[tx.i][tx.j][tx.k] == 'E'))
			{
				if(tu[tx.i][tx.j][tx.k]=='E') return temp2.step+1;
				book[tx.i][tx.j][tx.k]=true;
				q.push((node){tx.i,tx.j,tx.k,temp2.step+1});
			}
		}
	}
	return -1;
}
int main()
{
	while(1)
	{
		scanf("%d %d %d",&L,&R,&C);
		if(L==0&&R==0&&C==0) break;
		else
		{
			node qidian=(node){0,0,0,0};
			for(int i=1;i<=L;i++)
			{
				getchar();
				for(int j=1;j<=R;j++)
				{
					for(int w=1;w<=C;w++)
					{
						char c=getchar();
						tu[i][j][w]=c;
						if(c=='S')
						{
							qidian.i=i;
							qidian.j=j;
							qidian.k=w;
							qidian.step=0;
							book[i][j][w]=true;
						}
					}
					getchar();
				}
			}
			int ans=bfs(qidian);
			if(ans==-1) printf("No dress to appreciate!\n");
			else printf("%d\n",ans);
		}
	}
	return 0;
} 

2.2合并块问题

/*
eg1:给定一个m*n的矩阵,矩阵中的元素为0或1,称位置(x,y)与其上下左右四个位置(x,y+1),(x,y-1)(x+1,y)(x-1,y)是相邻的,(不必两两相邻,那么这些1就构成了一个块,求给定矩阵中的块的个数)
如该矩阵块为4
*/
/*
6 7
0 1 1 1 0 0 1 
0 0 1 0 0 0 0 
0 0 0 0 1 0 0  
0 0 0 1 1 1 0 
1 1 1 0 1 0 0 
1 1 1 1 0 0 0
*/
#include <stdio.h>
#include<iostream>
#include<queue>
using namespace std;
int daan=0;
const int maxn=100;
int n,m;
struct node
{
	int x;
	int y;
}temp,temp2,temp3,Node;
bool hash[maxn][maxn]={false};
int jilu[maxn][maxn];
int heng[5]={0,0,0,1,-1};
int shu[5]={0,1,-1,0,0};
bool test(int x,int y)
{
	if(x<1||x>n||y<1||y>m) return false;
	if(jilu[x][y]==0) return false;
	if(hash[x][y]==true) return false;
	return true;
}
int bfs()
{
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(!test(i,j)) continue;
			else
			{
				temp.x=i;
				temp.y=j;
				queue<node> q;
				q.push(temp);
				hash[temp.x][temp.y]=true;
				while(!q.empty())
				{
					temp2=q.front();
					q.pop();
					for(int w=1;w<=4;w++)
					{
						temp3.x=temp2.x+heng[w];
						temp3.y=temp2.y+shu[w];
						if(test(temp3.x,temp3.y))
						{
							hash[temp3.x][temp3.y]=true;
							q.push(temp3);
						}
					}
				}
				daan++;
			}
		}
	}
	return daan;
}
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++) scanf("%d",&jilu[i][j]);
	}
	printf("%d",bfs());
}

2.3注意队列是front()就行

/*
题目描述:
钓鱼岛是由一个主岛和一些附属岛屿组成,小哼决定去钓鱼岛探险。下面这个10*10的二维矩阵就是钓鱼岛的航拍地图。图中数字表示海拔,0表示海洋,1~9表示陆地。小哼的飞机将会降落在(6,8)处,现在需要计算出小哼降落地所在岛的面积(即有多少个格子)。
10 10 6 8
1 2 1 0 0 0 0 0 2 3
3 0 2 0 1 2 1 0 1 2
4 0 1 0 1 2 3 2 0 1
3 2 0 0 0 1 2 4 0 0
0 0 0 0 0 0 1 5 3 0
0 1 2 1 0 1 5 4 3 0
0 1 2 3 1 3 6 2 1 0
0 0 3 4 8 9 7 5 0 0
0 0 0 3 7 8 6 0 1 2
0 0 0 0 0 0 0 0 1 0
*/
#include<stdio.h>
#include<iostream>
#include<queue>
using namespace std;
int n,m;
struct node
{
	int x,y;
}Node,start;
int heng[5]={0,0,0,1,-1};
int shu[5]={0,1,-1,0,0};
int jilu[100][100];
bool hash[100][100]={false};
int geshu=0;
bool test(int x,int y)
{
	if(x<1||x>n||y<1||y>m) return false;
	if(hash[x][y]==true) return false;
	if(jilu[x][y]==0) return false;
	return true;
}
int bfs(int x,int y)
{
	queue<node> q;
	q.push(start);
	while(!q.empty())
	{
		node temp;
		temp=q.front();//这个是front()
		q.pop(); 
		for(int i=1;i<=4;i++)
		{
			Node.x=temp.x+heng[i];
			Node.y=temp.y+shu[i];
			if(test(Node.x,Node.y))
			{
				hash[Node.x][Node.y]=true;
				q.push(Node);
				geshu++;
			}
		}
	}
	return geshu+1;
}
int main()
{
	scanf("%d %d %d %d",&n,&m,&start.x,&start.y);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++) scanf("%d",&jilu[i][j]);
	}
	hash[start.x][start.y]=true;
	printf("%d",bfs(start.x,start.y));
	return 0;
}

3.暴力

3.1有技巧的暴力(减参枚举+贪心)

/*火柴棍等式
暴搜,有限制范围的枚举(有时候会用到贪心的一点知识),减参枚举,通过写函数减少重复过程
题目:用m(m <= 24)根火柴棍拼出A+B=C的等式,数字非零,则最高位不能是0,加号和等号各用了两根火柴棍,问可以拼出多少个不同等式?*/
#include<stdio.h>
int a[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
int fun(int n)
{
	if(n==0) return 6;//这个0的判断极为重要因为是0无法进循环转换 
	int sum=0;
	while(n!=0)
	{
		sum+=a[n%10];
		n=n/10;
	}
	return sum;
}
int main()
{
	int m;
	scanf("%d",&m);//要准确求解其实是711,可以自己编个程序看一看 
	for(int a=0;a<=1111;a++)//此处用到贪心 (此处从0开始)首先1能组成最大数其次3个数用的最少必定要平均分 
	{ 
		for(int b=0;b<=1111;b++)
		{
			int c=a+b;
			if(fun(a)+fun(b)+fun(c)+4==m)
			{
				printf("%d+%d=%d\n",a,b,c);
			}
		}
	}
	return 0;
}
 

3.2n皇后问题暴力

/*
硬是暴力算出
八皇后问题。八皇后问题是高斯先生在60多年以前提出来的,是一个经典的回溯算法问题。
其核心为:在国际象棋棋盘(8行8列)上摆放8个皇后,要求8个皇后中任意两个都不能位于同一行、同一列或同一斜线上。
 
*/ 
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
int daan=0;
int n;
int quanpailie[9];
bool hash[9]={false};
void dfs(int index)
{
	if(index==n+1)
	{
		int flag=0;
		for(int i=1;i<=n;i++)
		{
			for(int j=i+1;j<=n;j++)//这里稍微减少些时间复杂度 
			{
				if(abs(j-i)==abs(quanpailie[i]-quanpailie[j]))
				{
					flag=1;
					break;
				}
			}
		} 
		if(flag==0)
		{
			daan++;
			return;
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(hash[i]==false)
		{
			quanpailie[index]=i;//这里要填数别忘了 
			hash[i]=true;
			dfs(index+1);
			hash[i]=false;
		}
	}
	return;
}
int main()
{
	scanf("%d",&n);
	dfs(1);	
	printf("%d",daan);
	return 0;
}

3.3n皇后问题回溯法

//无比巧妙的回溯哈哈哈写出来了暴力回溯
/*
八皇后问题。八皇后问题是高斯先生在60多年以前提出来的,是一个经典的回溯算法问题。
其核心为:在国际象棋棋盘(8行8列)上摆放8个皇后,要求8个皇后中任意两个都不能位于同一行、同一列或同一斜线上。
 
*/ 
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
int daan=0;
int n;
int quanpailie[9];
bool hash[9]={false};
void dfs(int index)
{
	if(index==n+1)
	{
		daan++;
		return;	
	}
	for(int i=1;i<=n;i++)
	{
		if(hash[i]==false)
		{
			int flag=0;
			quanpailie[index]=i;//这里要填数别忘了 (此处回溯的时候要写在靠前位置)
			for(int j=1;j<index;j++)
			{
				if(abs(j-index)==abs(quanpailie[j]-quanpailie[index]))
				{
					flag=1;
					break;
				}
			}
			if(flag==0)
			{ 
				hash[i]=true;
				dfs(index+1);
				hash[i]=false;
			}
		}
	}
	return;
}
int main()
{
	scanf("%d",&n);
	dfs(1);	
	printf("%d",daan);
	return 0;
}

4图的遍历

4.1dfs(用于有权边有权点不考虑遍历层数)(一律按线性考虑因为记录数组是一维的)
存图

/*
邻接矩阵版 
*/ 
const int maxn=1000;
const int inf=100000000;
bool hash[maxn]={false};//就是点的个数 
int jilu[maxn][maxn];//最多这么多情况 
void dfs(int u,int deep)
{
	hash[u]=true;
	for(int i=1;i<=n;i++)
	{
		if(jilu[u][i]!=inf&&hash[i]==false) dfs(u,deep+1);//用两个条件限制 
	}//void当没啥子用的时候可加return 也可不加 ,当此处必须截断返回时则一定要加return 
}
void dfstrave()
{
	for(int i=1;i<=n;i++)
	{
		if(hash[i]==false) dfs(i,1);
	}
}
/*
邻接链表 
*/ 
const int maxn=1000;
bool hash[maxn]={false};
vector<int> jilu[maxn];
void dfs(int u,int deep)
{
	hash[u]=true;
	for(int i=0;i<jilu.size();i++)
	{
		int v=adj[u][i];//看得比较清楚 
		if(hash[v]==false) dfs(u,deep+1);
	}
}
void dfstrave()
{
	for(int i=1;i<=n;i++)
	{
		if(hash[i]==false) dfs(i,1);
	}
}
/*存图邻接链表*/
Node temp;
temp.v=3;
temp.w=4;
adj[1].push_back(temp);
==
struct Node
{
	int v,w;
	Node(){}//没有分号哦 
	Node(int _v,int _w) :v(_v),w(_w){}//没有;哦 
} 
adj[1].push_back(Node(3,4));//当结构体内的性质有许多的时候这种操作较为方便 

4.1.1(连通块都是要类比线性清楚标记的)

/*甲级head of gang 
One way that the police finds the head of a gang is to check people's phone calls. If there is a phone call between A and B, we say that A and B is related. The weight of a relation is defined to be the total time length of all the phone calls made between the two persons. A "Gang" is a cluster of more than 2 persons who are related to each other with total relation weight being greater than a given threshold K. In each gang, the one with maximum total weight is the head. Now given a list of phone calls, you are supposed to find the gangs and the heads.

Input Specification:

Each input file contains one test case. For each case, the first line contains two positive numbers N and K (both less than or equal to 1000), the number of phone calls and the weight threthold, respectively. Then N lines follow, each in the following format:

Name1 Name2 Time

where Name1 and Name2 are the names of people at the two ends of the call, and Time is the length of the call. A name is a string of three capital letters chosen from A-Z. A time length is a positive integer which is no more than 1000 minutes.

Output Specification:

For each test case, first print in a line the total number of gangs. Then for each gang, print in a line the name of the head and the total number of the members. It is guaranteed that the head is unique for each gang. The output must be sorted according to the alphabetical order of the names of the heads.

Sample Input 1:
8 59
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10
Sample Output 1:
2
AAA 3
GGG 3
Sample Input 2:
8 70
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10
Sample Output 2:
0
*/
#include<stdio.h>
#include<iostream>
#include<string>
#include<map>
using namespace std;
const int maxn=2010;
const int INF=10000000;
map<int,string> inttostring;
map<string,int> stringtoint;
map<string,int> gang;
int bian[maxn][maxn]={0};
int dian[maxn]={0};
int n,k,numperson=0;
bool hashtable[maxn]={false};
void dfs(int nowvisit,int &head,int &nummember,int &totalvalue)//每一个族的性质在这里体现 
{//此处也有坏处,虽然比指针好用但是只能传变量 
	nummember++;
	hashtable[nowvisit]=true;
	if(dian[nowvisit]>dian[head]) head=nowvisit;
	for(int i=0;i<numperson;i++)//此处不等于numperson的原因并不是有这么多个而是因为change多加了一个所以。。。(而且不能写n。。。)
	{
		if(bian[nowvisit][i]>0)
		{
			totalvalue+=bian[nowvisit][i];
			bian[nowvisit][i]=bian[i][nowvisit]=0;//删除边(防止回头 )与平常的深搜不一样(其实只删一个边也没有错但为了不搞混就全删了吧)(i不能和head混了)
			if(hashtable[i]==false) dfs(i,head,nummember,totalvalue); //这里是防止成环(这种特殊情况)错误 
		}
	}
}
void dfstrave()
{
	for(int i=0;i<numperson;i++)//此处不等于numperson的原因并不是有这么多个而是因为change多加了一个所以。。。 
	{
		if(hashtable[i]==false)
		{
			int head=i,nummember=0,totalvalue=0;
			dfs(i,head,nummember,totalvalue);
			if(nummember>2&&totalvalue>k) gang[inttostring[head]]=nummember;//是头头转化为string建立map对应团队人数nummember 
		}
	}
}
/*
void dfstrave()
{
	for(int i=0;i<numperson;i++)
	{
		int head=i,nummember=0,totalvalue=0;//目的是将head传出来 ,还有c++引用的时候只能穿变量 
		if(hashtable[i]==false) dfs(i,head,nummember,totalvalue);
		if(nummember>2&&totalvalue>k) gang[inttostring[head]]=nummember;
	}
}
*/
int change(string str)//此处是string与int建立联系的过程 
{
	if(stringtoint.find(str)!=stringtoint.end()) return stringtoint[str];//这里直接return即可 
	else
	{
		stringtoint[str]=numperson;
		inttostring[numperson]=str;
		return numperson++;//此处多加一个要注意 (注意此处有返回值了) 
	}
}
int main()
{
	int w;
	string str1,str2;
	cin>> n>> k;
	for(int i=0;i<n;i++)//第一遍遍历建图(边权和点权)(还有字符串对数字的映射)
	{
		cin >> str1 >> str2 >> w;
		int id1=change(str1);
		int id2=change(str2);
		dian[id1]+=w;
		dian[id2]+=w;
		bian[id1][id2]+=w;
		bian[id2][id1]+=w;	
	} 
	dfstrave();
	cout << gang.size() << endl;
	map<string,int>::iterator it;
	for(it=gang.begin();it!=gang.end();it++) cout << it->first << " " << it->second << endl;	 
	return 0;
}

4.1.2全搜一遍之dfs的最短路

/*
全搜一遍之最短路 dfs 
*/
#include<stdio.h>
#include<iostream>
#include<vector>
using namespace std;
struct node
{
	int id;
	int bianquan;
};
int chengshi,gonglu;
const int maxn=1010;
vector <node> jilu[maxn];
bool hashtable[maxn]={false};
int min1=9999;
void dfs(int n,int sum)//相关族的属性 
{
	if(sum>min1) return;
	if(n==5)
	{
		if(sum<min1) min1=sum;
	}
	for(int i=0;i<jilu[n].size();i++)
	{
		if(hashtable[i]==false)
		{
			hashtable[i]=true;
			dfs(jilu[n][i].id,sum+jilu[n][i].bianquan);
			hashtable[i]=false;//线性记录就要恢复 
		}
	}
}
int main()
{
	scanf("%d %d",&chengshi,&gonglu);
	for(int i=1;i<=gonglu;i++)
	{
		int a,b,c;
		scanf("%d %d %d",&a,&b,&c);
		node temp={b,c};
		jilu[a].push_back(temp);
	}
	dfs(1,0);
	printf("%d",min1);
	return 0;
}
/*
5 8
1 2 2
1 5 10
2 3 3
2 5 7
3 1 4
3 4 4
4 5 5
5 3 3
*/

4.2bfs板子

//bfs板子
bfs(u)
{
	queue q;
	//将u入队
	while(!q.empty())
	{
		//取出q的队首元素u进行访问
		for(从u出发可到达的所有顶点)
		{
		//剔除队首元素 
			if(hashtable[v]==false)
			{
				//将v入队
				hashtable[v]=true; 
			}
		} 
	} 
} 
void bfs(G)//遍历图G
{
	for(G所有顶点)
	{
		if(hashtable[u]==false) bfs(u);
	}
} 

存图

int n,g[maxn][maxn];//初始化为INF 
bool hashtable[maxn]={false};
void bfs(int u)
{
	queue <int>q;
	q.push(u);
	hashtable[u]=true;//初始化别少了这个 
	while(!q.empty())
	{
		int v=q.front();
		q.pop();
		for(i=0;i<n;i++)
		{
			if(g[v][i]!=INF&&hashtable[i])
			{
				q.push(g[v][i]);
				hashtable[i]=true;
			}
		}
	}
} 
void bfstrave()
{
	for(int u=0;u<n;u++)
	{
		if(hashtable[u]==false) bfs(u);
	}
}

4.2.1bfs遍历

这里用dfs不方便(因为是遍历层数的问题用dfs会有情况找不出来)

/*
1076 Forwards on Weibo (30分)
Weibo is known as the Chinese version of Twitter. One user on Weibo may have many followers, and may follow many other users as well. Hence a social network is formed with followers relations. When a user makes a post on Weibo, all his/her followers can view and forward his/her post, which can then be forwarded again by their followers. Now given a social network, you are supposed to calculate the maximum potential amount of forwards for any specific user, assuming that only L levels of indirect followers are counted.

Input Specification:
Each input file contains one test case. For each case, the first line contains 2 positive integers: N (≤1000), the number of users; and L (≤6), the number of levels of indirect followers that are counted. Hence it is assumed that all the users are numbered from 1 to N. Then N lines follow, each in the format:

M[i] user_list[i]

      
    
where M[i] (≤100) is the total number of people that user[i] follows; and user_list[i] is a list of the M[i] users that followed by user[i]. It is guaranteed that no one can follow oneself. All the numbers are separated by a space.

Then finally a positive K is given, followed by K UserID's for query.

Output Specification:
For each UserID, you are supposed to print in one line the maximum potential amount of forwards this user can trigger, assuming that everyone who can view the initial post will forward it once, and that only L levels of indirect followers are counted.

Sample Input:
7 3
3 2 3 4
0
2 5 6
2 3 1
2 3 4
1 4
1 5
2 2 6

      
    
Sample Output:
4
5
*/
#include<stdio.h>//bfs用于层数及无权边 (多次遍历不会易恢复图)
#include<vector>
#include<iostream>
#include<queue>
#include<string.h>//用作memset 
using namespace std;
int l; 
const int maxn=1010;
struct node
{
	int id;
	int layer;
};//此处有分号!!!!!! 
vector<node> jilu[maxn];//相当于二维数组(这个时候最后就不用数组形式了,因为push_back()更方便) 
bool hashtable[maxn]={false}; 
int bfs(int s)//s是顶点id,l是遍历层数(要求的) 
{
	int zhuanfashu=0;
	queue<node> q;//开始的步骤 
	node start={s,0};
	q.push(start);
	hashtable[start.id]=true;
	while(!q.empty())
	{
		node top;//一般都叫top 
		top=q.front();
		q.pop();//少括号 (别忘了这一步) 
		for(int i=0;i<jilu[top.id].size();i++)
		{
			node next;
			next=jilu[top.id][i];//前后呼应 进出一致 
			next.layer=top.layer+1;
			if(hashtable[next.id]==false&&next.layer<=l)
			{
				q.push(next);
				hashtable[next.id]=true;
				zhuanfashu++;
			}
		}	
	}
	return zhuanfashu;
}
int main()
{
	int n;
	scanf("%d %d",&n,&l);
	for(int i=1;i<=n;i++)
	{
		int f;
		scanf("%d",&f);
		for(int j=1;j<=f;j++)
		{
			int a;//a就是先 
			scanf("%d",&a);
			node temp={i,0};
			jilu[a].push_back(temp);//前后呼应 ,编号确实是从1开始 
		}//输入正好相反(难点) 
	}
	int n2;
	scanf("%d",&n2);
	for(int i=1;i<=n2;i++)
	{
		memset(hashtable,false,sizeof(hashtable));//一步一清零 
		int s;
		scanf("%d",&s);
		printf("%d\n",bfs(s));
	}
	return 0;
}

4.2.2最少转机

/*
5 7 1 5
1 2
1 3
2 3
2 4
3 4
3 5
4 5
 当你和家人一起去海南旅游,可是你的城市并没有直接到达海南的飞机,但是你已经搜集了很多航班的信息,现在你希望找到一种乘坐方式,使得转机次数最少

如何解决呢?  

  假如你的城市在1号城市,海南在5号城市;现有如下关系:
*/
#include<stdio.h>
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
const int maxn=1010;
struct node
{
	int bianhao;
	int step;//记录每一步的属性 
};
bool jilu[maxn]={false};
vector<node> tu[maxn]; 
int bfs(int qidian,int zhongdian)
{
	queue<node> q;
	node temp={qidian,0};
	q.push(temp);
	jilu[qidian]=true;
	while(!q.empty())
	{
		node temp1=q.front();
		q.pop();
		for(int i=0;i<tu[temp1.bianhao].size();i++)
		{
			if(tu[temp1.bianhao][i].bianhao==zhongdian) return temp1.step;//此处注意将vector的扩展写出方便查看 
			if(jilu[i]==false)
			{
				jilu[i]=true;
				node temp2={i,temp1.step+1};
				q.push(temp2);
			}
		}
	} 
}
int main()
{
	int a,b,c,d;
	scanf("%d %d %d %d",&a,&b,&c,&d);
	for(int i=0;i<b;i++)
	{
		int g,h;
		scanf("%d %d",&g,&h);
		node temp3={g-1,0};
		node temp4={h-1,0};
		tu[g-1].push_back(temp4);//既然用了这种形式的vector那就将0用上吧 (有时候题目上从1开始编号所以。。要减一) 
		tu[h-1].push_back(temp3);
	}
	cout<< bfs(c-1,d-1) << endl;
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一 。课程设计题目:漫步迷宫 二 。问题描述: 用m行n列的m*n个正方格表示一个迷宫,其中划有斜线的方格表示不可通行,未划有斜线的方格表示可以通行。请编写寻找从入口到出口的一条最短路径的程序。 三 。基本要求: 1。迷宫的规格(即行数与列数),状态设置(即各方格能否通行的状态),以及入口和出口的位置,均应由输入随机确定。 2。求得的最短路径,应该以从入口到出口的路径上的各个方格的坐标的线性序列输出。当无通路时,应该报告无路径的信息。 3。尽量采用结构化程序设计方法,要求对各个模块的功能及参数作必要的说明。 四 。实现提示: 1。迷宫可以采用matrix类型的二维数组A表示。A.rownum与A.colnum分别表示迷宫的实际的行数与列数。而A.maze[i][j]表示迷宫中第i行第j列的一个方格,用A.maze[i][j]=0表示该方格可以通行,用A.maze[i][j]=1表示该方格不可以通行。 2。由于要寻找从入口到出口的一条最短路径,最好将迷宫看作是一个图结构。则问题转化为寻找从对应于入口顶点到对应于出口顶点的一条最短路径的问题。该问题可以采用从入口顶点出发,进行广度优先搜索遍历,直到遇到出口顶点或者遍历完毕也没有遇到出口顶点为止。这二种情况分别对应于最短路径探索成功与查无通路的事实。 3。基于上述分析,涉及到数据结构的转换,即将二维数组表示的迷宫A转换为以adjlist 类型的邻接表表示的图结构G。在图结构中,将迷宫中的每个方格看作是一个顶点。不可通行的方格都是孤立顶点;相邻的可通行的方格所对应的顶点之间看作是有边相连。因此迷宫 可以看作是由m*n个顶点及无向边构成的一个非连通的无向图。尽管图是不连通的,但不影响本问题的求解,而且本问题有解的条件是:入口顶点与出口顶点在同一个连通分量中。 图结构G中,G.adj[k]表示编号为k的顶点的邻接情况的单链表的头指针;G.vexnum表示图G中的实际顶点数,而且具有如下关系:G.vexnum=A.rownum*A.colnum 4。为了避免迷宫数据的重复输入,我们期望A能够自动地转换为G。因此应该设计一个转换算法create_adjlist(A,G)。而图结构中顶点是要编号的,我们约定以行为序,顺序给迷宫A中的方格所对应的顶点编号。这样迷宫中方格的坐标(即行row和列col)与图G中所对应的顶点的编号(即verno)之间具有如下关系: verno=(row-1)* n + col row=(verno-1)/ n + 1 col=(verno-1)% n + 1 5。在广度优先搜索遍历求解最短路径过程中,应该设置一个队列queue作为辅助数据结构;路径采用一个整数数组pred来表示。这二个数据结构的存储结构类型均为list类型,其说明定义如下:typedef int list[MAXVER]; 队列queue应该设置front和rear分别指示列首与列尾,queue[k]表示第k个入列的顶点编号。采用pred记录路径,pred[i]表示顶点i在广度优先搜索遍历过程中的前趋顶点的编号,它表明是经过边(pred[i],i)达到顶点i的。这样,当路径探索成功时,我们可以从出口顶点倒推出从入口到出口的一条路径来。当然要涉及到从顶点编号向方格坐标的反转换,这个公式在上面已经给出了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值