搜索
- 通过不停的试探去寻找解的一种算法, 更像是一种方法。 暴力搜, 深搜, 广搜。
- 深搜
例题一、 排列组合问题:
深搜解法:
#include <iostream>
#include <algorithm>
using namespace std;
int a[10], book[10];
int n;
void dfs(int st)
{
if(st == n + 1){
for(int i = 1; i <= n; i ++) cout << a[i] << " ";
cout << endl;
return ;
}
for(int i = 1; i <= n; i ++){
if(!book[i]){
book[i] = 1;
a[st] = i;
dfs(st + 1);
book[i] = 0;
}
}
}
int main()
{
cin >> n;
dfs(1);
return 0;
}
例题二、
#include <iostream>
#include <algorithm>
using namespace std;
int a[1000];
int n, sum;
void dfs(int st, int k, int m)
{
if(st == k + 1){
if(m == 0){
printf("%d=%d", n, a[1]);
for(int i = 2; i <= k; i ++) printf("+%d", a[i]);
printf("\n");
sum ++;
}
return ;
}
for(int i = a[st - 1]; i <= m / (k - st + 1); i ++){
a[st] = i;
dfs(st + 1, k, m - i);
}
}
int main()
{
cin >> n;
a[0] = 1;
for(int i = 1; i <= n; i ++){
dfs(1, i, n);
}
cout << sum;
return 0;
}
例题三、走迷宫问题
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
ll n, m, minn = 0x3fffffff;
ll a[505][505], book[505][505];
ll dx[5] = {0, 1, 0, -1};
ll dy[5] = {1, 0, -1, 0};
void dfs(int x, int y, ll st)
{
ll tx, ty, k;
if(x == n - 1 && y == n - 1){
if(st < minn) minn = st;
return ;
}
for(k = 0; k < 4; k ++){
tx = x + dx[k];
ty = y + dy[k];
if(tx < 0 || tx > n - 1 || ty < 0 || ty > n - 1) continue;
if(book[tx][ty] == 0 &&a[tx][ty] == 0){
book[tx][ty] = 1;
dfs(tx, ty, st + 1);
book[tx][ty] = 0;
}
}
}
int main()
{
scanf("%lld", &n);
for(ll i = 0; i < n; i++){
for(ll j = 0; j < n; j ++){
scanf("%lld", &a[i][j]);
}
}
book[0][0] = 1;
dfs(0, 0, 0);
printf("%lld\n", minn);
return 0;
}
- 广搜
#include <iostream>
#include <algorithm>
using namespace std;
int arr[501][501];
int book[501][501];
int dx[5] ={0, 1, 0, -1};//规定四个方向
int dy[5]= {1, 0, -1, 0};
struct f {
int x;
int y;
int s;
}map[2500];
int n;
void bfs()
{
int tail = 1, head = 1;
map[tail].x = 0, map[tail].y = 0;
map[tail].s = 0;
book[0][0] = 1;
tail++;
while (head < tail)
{
int k = 0;
for (int i = 0; i < 4; i++){
int nx = map[head].x + dx[i];
int ny = map[head].y + dy[i];
if (nx<0 || nx>n - 1 || ny<0 || ny>n - 1)
continue;
if (book[nx][ny] == 0 && arr[nx][ny] == 0){
book[nx][ny] = 1;
map[tail].x = nx;
map[tail].y = ny;
map[tail].s = map[head].s + 1;
tail++;
}
if (nx == n-1 && ny == n-1){
k = 1;
cout << map[tail - 1].s;
break;
}
}
if (k == 1) break;
head++;
}
}
int main(void)
{
cin >> n;
for (int i = 0; i < n; i++){
for (int j = 0; j < n; j++)
scanf("%d", &arr[i][j]);
}
bfs();
return 0;
}
最短路
- 多源最短路
- 概念:任意两点的最短距离
- 思想:用每一个点作为中转点, 进行“松弛” 操作。
#include <iostream>
using namespace std;
int a[105][105], b[10005];
int m, n;
int main()
{
cin >> n >> m;
for(int i = 1; i <= m; i ++) cin >> b[i];
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++){
cin >> a[i][j];
}
}
for(int k = 1; k <= n; k++){
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++){
if(a[i][j] > a[i][k] + a[k][j])
a[i][j] = a[i][k] + a[k][j];
}
}
}
int ans = 0;
for(int i = 1; i < m; i ++) ans += a[b[i]][b[i + 1]];
cout << ans;
}
- 单源最短路
- 某一个点到其他点的最短距离
- 思想:把所有点分为两个阵营, 一个为已求出最短距离阵营,另一个为未求出最短距离阵营。把每一个未求出最短距离阵营的点依次加入到求出最短距离阵营(每次找的是离求出最短距离阵营最近的点),并用这个点作为中转点,进行“松弛“操作。
#include <iostream>
using namespace std;
int a[505][505];
int dis[505];
int book[505];
const int inf = 0x3f3f3f3f;
int n, m;
void f()
{
book[1] = 1;
for(int i = 1; i <= n - 1; i ++){
int minn = inf;
int u;
for(int j = 1; j <= n; j++){
if(book[j] == 0 && dis[j] < minn){
minn = dis[j];
u = j;
}
}
book[u] = 1;
for(int j = 1; j <= n; j ++){
if(book[j] == 0 && dis[j] > dis[u] + a[u][j])
dis[j] = dis[u] + a[u][j];
}
}
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(i == j) a[i][j] = 0;
else a[i][j] = inf;
}
}
while(m --){
int x, y, z;
cin >> x >> y >> z;
if(a[x][y] > z)
a[x][y] = z;
}
for(int i = 1; i <= n; i ++){
dis[i] = a[1][i];
}
f();
if(dis[n] < inf)
cout << dis[n] ;
else cout << -1;
return 0;
}