搜索
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个元素理解为自然数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 )。
输出
所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,所有的组合也按字典顺序。
#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;
}