一、DFS(深度优先搜索)
- 数据结构:栈,stack
- 全排列,n-皇后问题
//全排列
#include <iostream>
#include <stdio.h>
using namespace std;
const int N = 10;
int n;
int path[N];
bool st[N];
void dfs(int u)
{
if(u == n)
{
for(int i=0;i<n;i++)
printf("%d",path[i]);
puts("");
return;
}
for(int i=1;i<=n;i++)
{
if(!st[i])
{
path[u] = i;
st[i] = true;
dfs(u+1);
st[i] = false;
}
}
}
int main()
{
cin >> n;
dfs(0);
return 0;
}
全排列的思想解决n皇后问题:
其中deg[]表示同一对角线上是否摆放了皇后,udeg[]表示同一反对角线上是否摆放了皇后。在坐标轴中可知,若在同一对角线上,则每个点的横纵坐标之差是相同的。
//n-皇后问题,全排列思想
#include <iostream>
#include <stdio.h>
using namespace std;
const int N = 20;
int n;
char g[N][N] ;
bool col[N],deg[N],udeg[N];
void dfs(int u)
{
if(u == n)
{
for(int i=0;i<n;i++)
puts(g[i]);
puts("");
return;
}
for(int i=0;i<n;i++)
{
if(!col[i] && !deg[u+i] && !udeg[n-u+i])
{
g[u][i] = 'Q';
col[i] = true;
deg[u+i] = true;
udeg[n-u+i] = true;
dfs(u+1);
col[i] = false;
deg[u+i] = false;
udeg[n-u+i] = false;
g[u][i] = '.';
}
}
}
int main()
{
cin >> n;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
g[i][j] = '.';
dfs(0);
return 0;
}
//行列分开判断
#include <iostream>
#include <stdio.h>
using namespace std;
const int N = 20;
int n;
char g[N][N] ;
bool row[N],col[N],deg[N],udeg[N];
void dfs(int x,int y,int c)
{
if(y == n)
{
y = 0;
x++;
}
if(x == n)
{
if(c == n)
{
for(int i=0;i<n;i++)
puts(g[i]);
puts("");
}
return;
}
//放皇后
if(!row[x] && !col[y] && !deg[x+y] && !udeg[n-x+y])
{
g[x][y] = 'Q';
row[x] = col[y] = deg[x+y] = udeg[n-x+y] = true;
dfs(x,y+1,c+1);
row[x] = col[y] = deg[x+y] = udeg[n-x+y] = false;
g[x][y] = '.';
}
//不放皇后
dfs(x,y+1,c);
}
int main()
{
cin >> n;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
g[i][j] = '.';
dfs(0,0,0);
return 0;
}
二、BFS(广度优先搜索)
解决最短路径问题
- 数据结构:队列,queue
- 走迷宫
//迷宫问题#include <iostream>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
using namespace std;
typedef pair<int,int> PII;
const int N = 110;
int g[N][N],m,n;
int dx[4]={1,0,0,-1},dy[4]={0,-1,1,0};
int d[N][N];
PII path[N][N];
stack<PII> s;
int bfs()
{
int i=0;
queue<PII> q;
q.push({0,0});
memset(d,-1,sizeof d);
d[0][0] = 0;
path[0][0] = {-1,-1};
while(q.size())
{
PII t = q.front();
q.pop();
for(int i=0;i<4;i++)
{
int x = t.first+dx[i];
int y = t.second+dy[i];
if(x>=0 && x<n && y>=0 && y<m && d[x][y]==-1 && !g[x][y])
{
d[x][y] = d[t.first][t.second]+1;
path[x][y] = t;
q.push({x,y});
}
}
}
int x=n-1,y=m-1;
while(x || y)
{
s.push({x,y});
PII t = path[x][y];
x = t.first,y = t.second;
}
return d[n-1][m-1];
}
int main()
{
cin >> n >> m;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin >> g[i][j];
cout << bfs() << endl;
while(s.size())
{
cout << s.top().first << " " << s.top().second << endl;
s.pop();
}
return 0;
}
三、树与图的存储
const int N = 100010,M=N*2;
int h[N],e[N],ne[N],idx;
void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx;
idx++;
}
四、树与图的深度优先遍历
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010;
int n;
int h[N],e[N],ne[N],idx;
bool st[N];
int ans = N;
void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx;
idx++;
}
//以u为根的子树中的点的数量
int dfs(int u)
{
st[u] = true;
int sum = 1,res=0;
for(int i=h[u];i!=-1;i=ne[i])
{
int j = e[i];
if(!st[j])
{
int s = dfs(j);
res = max(s,res);
sum += s;
}
}
res = max(res,n-sum);
ans = min(ans,res);
return sum;
}
int main()
{
cin >> n;
memset(h,-1,sizeof h);
for(int i=0;i<n-1;i++)
{
int a,b;
cin >> a >> b;
add(a,b);
add(b,a);
}
dfs(1);
cout << ans << endl;
return 0;
}
五、树与图的广度优先遍历
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010;
int n,m;
int h[N],e[N],ne[N],idx;
int d[N],q[N];
void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx;
idx++;
}
int bfs()
{
int hh=0,tt=0;
q[0] = 1;
memset(d,-1,sizeof d);
d[1] = 0;
while(hh <= tt)
{
int t = q[hh++];
for(int i=h[t];i!=-1;i=ne[i])
{
int j = e[i];
if(d[j] == -1)
{
d[j] = d[t]+1;
q[++tt] = j;
}
}
}
return d[n];
}
int main()
{
cin >> n >> m;
memset(h,-1,sizeof h);
for(int i=0;i<m;i++)
{
int a,b;
cin >> a >> b;
add(a,b);
}
cout << bfs() << endl;
return 0;
}
六、拓扑排序
有向无环图,广度优先搜索
#include <iostream>
#include <cstring>
#include <stdio.h>
using namespace std;
const int N = 100010;
int n,m;
int h[N],e[N],ne[N],idx;
int d[N],q[N];
void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx;
idx++;
}
int topsort()
{
int hh=0,tt=-1;
for(int i=1;i<=n;i++)
if(!d[i])
q[++tt] = i;
while(hh <= tt)
{
int t = q[hh++];
for(int i=h[t];i!=-1;i=ne[i])
{
int j = e[i];
d[j]--;
if(d[j]==0)
q[++tt] = j;
}
}
return tt == n-1;
}
int main()
{
cin >> n >> m;
memset(h,-1,sizeof h);
for(int i=0;i<m;i++)
{
int a,b;
cin >> a >> b;
add(a,b);
d[b]++;
}
if(topsort())
{
for(int i=0;i<n;i++)
printf("%d ",q[i]);
puts("");
}
else
puts("-1");
return 0;
}
七、最短路径问题
7.1 朴素dijkstra算法
- 初始化距离,源点dist[0]=0,其余dist=∞。
- 循环n次,找到源点到每个点的最短距离。
- 适合稠密图。
#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;
const int N = 510;
int n,m;
int dist[N];
int g[N][N];
bool st[N];
int dijkstra()
{
memset(dist,0x3f,sizeof dist);
dist[1] = 0;
for(int i=0;i<n;i++)
{
int t = 0;
for(int j=1;j<=n;j++)
if(!st[j] && dist[j]<dist[t])
t = j;
st[t] = true;
for(int j=1;j<=n;j++)
dist[j] = min(dist[j],dist[t]+g[t][j]);
}
if(dist[n] == 0x3f3f3f3f)
return -1;
else
dist[n];
}
int main()
{
scanf("%d%d",&n,&m);
memset(g,0x3f,sizeof g);
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
g[a][b] = c;
}
cout << dijkstra() << endl;
return 0;
}