暑假训练二阶段day1

本文介绍了如何使用Breadth First Search (BFS) 和 Depth First Search (DFS) 算法解决实际问题,包括寻找最短路径、演示DFS遍历并记录时间戳,以及在二维迷宫和DNA序列中找出最短连接。通过实例展示了如何在信息技术背景下应用这两种经典算法。
摘要由CSDN通过智能技术生成

Breadth First Search

Write a program which reads an directed graph G = ( V , E ) G = (V, E) G=(V,E), and finds the shortest distance from vertex 1 1 1 to each vertex (the number of edges in the shortest path). Vertices are identified by IDs 1 , 2 , . . . n 1, 2, ... n 1,2,...n.
Input

In the first line, an integer n n n denoting the number of vertices, is given. In the next n n n lines, adjacent lists of vertex u u u are given in the following format:

u u u k k k v 1 v_1 v1 v 2 v_2 v2 v k v_k vk

u u u is ID of the vertex and k k k denotes its degree. v i v_i vi are IDs of vertices adjacent to u u u.
Constraints

$1 \leq n \leq 100$

Output

For each vertex u u u, print i d id id and d d d in a line. i d id id is ID of vertex u u u and d d d is the distance from vertex 1 1 1 to vertex u u u. If there are no path from vertex 1 1 1 to vertex u u u, print -1 as the shortest distance. Print in order of IDs.
Sample Input 1

4
1 2 2 4
2 1 4
3 0
4 1 3

Sample Output 1

1 0
2 1
3 2
4 1

Reference

Introduction to Algorithms, Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein. The MIT Press.

题解:如题名bfs

#include<iostream>
#include<queue>
using namespace std;

const int N = 1e2+10;

int a[N][N], vis[N], w[N];
int n;

void bfs()
{
    queue<int> q;
    q.push(1);
    w[1] = 0;
    while(!q.empty())
    {
        int u = q.front();
        vis[u] = 1;
        q.pop();
        for(int i = 2; i <= n; i++)
        {
            if(a[u][i] == 1 && vis[i] == 0)
            {
                w[i] = w[u] + 1;
                vis[i] = 1;
                q.push(i);
            }
        }
    }
}


int main(void)
{
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        int u,v,k;
        cin >> u >> k;
        w[i] = -1;
        for(int j = 1; j <= k; j++)
        {
            cin >> v;
            a[u][v] = 1;
        }
    }
    bfs();
    for (int i = 1; i <= n; i++) {
        cout << i << " " << w[i] << endl;
    }
}

Depth First Search

Depth-first search (DFS) follows the strategy to search ”deeper” in the graph whenever possible. In DFS, edges are recursively explored out of the most recently discovered vertex v v v that still has unexplored edges leaving it. When all of v v v's edges have been explored, the search ”backtracks” to explore edges leaving the vertex from which v v v was discovered.

This process continues until all the vertices that are reachable from the original source vertex have been discovered. If any undiscovered vertices remain, then one of them is selected as a new source and the search is repeated from that source.

DFS timestamps each vertex as follows:

$d[v]$ records when $v$ is first discovered.
$f[v]$ records when the search finishes examining $v$’s adjacency list.

Write a program which reads a directed graph G = ( V , E ) G = (V, E) G=(V,E) and demonstrates DFS on the graph based on the following rules:

$G$ is given in an adjacency-list. Vertices are identified by IDs $1, 2,... n$ respectively.
IDs in the adjacency list are arranged in ascending order.
The program should report the discover time and the finish time for each vertex.
When there are several candidates to visit during DFS, the algorithm should select the vertex with the smallest ID.
The timestamp starts with 1.

Input

In the first line, an integer n n n denoting the number of vertices of G G G is given. In the next n n n lines, adjacency lists of u u u are given in the following format:

u u u k k k v 1 v_1 v1 v 2 v_2 v2 v k v_k vk

u u u is ID of the vertex and k k k denotes its degree. v i v_i vi are IDs of vertices adjacent to u u u.
Output

For each vertex, print i d id id, d d d and f f f separated by a space character in a line. i d id id is ID of the vertex, d d d and f f f is the discover time and the finish time respectively. Print in order of vertex IDs.
Constraints

$1 \leq n \leq 100$

Sample Input 1

4
1 1 2
2 1 4
3 0
4 1 3

Sample Output 1

1 1 8
2 2 7
3 4 5
4 3 6

Sample Input 2

6
1 2 2 3
2 2 3 4
3 1 5
4 1 6
5 1 6
6 0

Sample Output 2

1 1 12
2 2 11
3 3 8
4 9 10
5 4 7
6 5 6

This is example for Sample Input 2 (discover/finish)
Reference

Introduction to Algorithms, Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein. The MIT Press.

题解:如题名dfs

#include<iostream>

using namespace std;
const int N = 1e2 + 10;
int d[N], f[N], a[N][N], cnt = 1, n;

int dfs(int x) {
    d[x] = cnt++;
    for (int i = 1; i <= n; i++)
        if (a[x][i] && d[i] == 0)dfs(i);
    f[x] = cnt++;
}

int main(void) {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        int u, v, k;
        cin >> u >> k;
        for (int j = 0; j < k; j++) {
            cin >> v;
            a[u][v] = 1;
        }
    }
    for (int i = 1; i <= n; i++)
        if (d[i] == 0)
            dfs(i);
    for (int i = 1; i <= n; i++)
        cout << i << " " << d[i] << " " << f[i] << endl;
    return 0;
}

非常可乐

 大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为。因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多。但seeyou的手中只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升 (正好装满一瓶) ,它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。聪明的ACMER你们说他们能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出"NO"。 

Input
三个整数 : S 可乐的体积 , N 和 M是两个杯子的容量,以"0 0 0"结束。
Output
如果能平分的话请输出最少要倒的次数,否则输出"NO"。
Sample Input

7 4 3
4 1 3
0 0 0

Sample Output

NO
3

题解

Amazing Mazes

Problem B:

You are requested to solve maze problems. Without passing through these mazes, you might not be able to pass through the domestic contest!

A maze here is a rectangular area of a number of squares, lined up both lengthwise and widthwise, The area is surrounded by walls except for its entry and exit. The entry to the maze is at the leftmost part of the upper side of the rectangular area, that is, the upper side of the uppermost leftmost square of the maze is open. The exit is located at the rightmost part of the lower side, likewise.

In the maze, you can move from a square to one of the squares adjoining either horizontally or vertically. Adjoining squares, however, may be separated by a wall, and when they are, you cannot go through the wall.

Your task is to find the length of the shortest path from the entry to the exit. Note that there may be more than one shortest paths, or there may be none.
Input

The input consists of one or more datasets, each of which represents a maze.

The first line of a dataset contains two integer numbers, the width w and the height h of the rectangular area, in this order.

The following 2 × h − 1 lines of a dataset describe whether there are walls between squares or not. The first line starts with a space and the rest of the line contains w − 1 integers, 1 or 0, separated by a space. These indicate whether walls separate horizontally adjoining squares in the first row. An integer 1 indicates a wall is placed, and 0 indicates no wall is there. The second line starts without a space and contains w integers, 1 or 0, separated by a space. These indicate whether walls separate vertically adjoining squares in the first and the second rows. An integer 1/0 indicates a wall is placed or not. The following lines indicate placing of walls between horizontally and vertically adjoining squares, alternately, in the same manner.

The end of the input is indicated by a line containing two zeros.

The number of datasets is no more than 100. Both the widths and the heights of rectangular areas are no less than 2 and no more than 30.

Output

For each dataset, output a line having an integer indicating the length of the shortest path from the entry to the exit. The length of a path is given by the number of visited squares. If there exists no path to go through the maze, output a line containing a single zero. The line should not contain any character other than this number.
Sample Input

2 3
1
0 1
0
1 0
1
9 4
1 0 1 0 0 0 0 0
0 1 1 0 1 1 0 0 0
1 0 1 1 0 0 0 0
0 0 0 0 0 0 0 1 1
0 0 0 1 0 0 1 1
0 0 0 0 1 1 0 0 0
0 0 0 0 0 0 1 0
12 5
1 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0 0
1 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1 0 0 0 0
0 0 1 0 0 1 0 1 0 0 0
0 0 0 1 1 0 1 1 0 1 1 0
0 0 0 0 0 1 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0
0 0

Output for the Sample Input

4
0
20

题意:建地图的迷宫

题解:建图后,直接搜

#include <iostream>
#include <string.h>
#include <vector>
#include <queue>
using namespace std;


int w, h;
int map[70][70], exit_i, exit_j;
int dist[70][70];
int dx[4] = {0, 2, 0, -2};
int dy[4] = {2, 0, -2, 0};

struct node {
    int x;
    int y;
};

void make_map(int w, int h) {
    int i, j;
    memset(map, 0, sizeof(map));
    for (i = 0; i <= 2 * h; i++) {
        if (i == 0 || i == 2 * h) {
            for (j = 0; j <= 2 * w; j++) {
                map[i][j] = 1;
            }
        } else {
            map[i][0] = map[i][2 * w] = 1;
        }
    }
    map[0][1] = map[2 * h][2 * w - 1] = 0;
    for (i = 1; i <= 2 * h - 1; i++) {
        if (i % 2 == 1) {
            for (j = 0; j < w - 1; j++) {
                cin >> map[i][2 * j + 2];
            }
        } else {
            for (j = 0; j < w; j++) {
                cin >> map[i][2 * j + 1];
            }
        }
    }
    exit_i = 2 * h - 1;
    exit_j = 2 * w - 1;
}

int bfs() {
    queue<node> q;
    for (int i = 0; i < 65; i++) {
        for (int j = 0; j < 65; j++) {
            dist[i][j] = 0x3f3f3f3f;
        }
    }
    q.push(node{1, 1});
    dist[1][1] = 0;
    while (q.size()) {
        node p = q.front();
        q.pop();
        if (p.x == exit_i && p.y == exit_j)
            break;
        for (int i = 0; i < 4; i++) {
            int x = p.x + dx[i];
            int y = p.y + dy[i];
            if (1 <= x && x < 2 * h && 1 <= y && y < 2 * w
                && map[(x + p.x) / 2][(y + p.y) / 2] == 0
                && map[x][y] == 0
                && dist[x][y] == 0x3f3f3f3f) {
                q.push(node{x, y});
                dist[x][y] = dist[p.x][p.y] + 1;
            }
        }
    }
    return dist[exit_i][exit_j] + 1;
}

int main(void) {
    while (cin >> w >> h && w && h) {
        make_map(w, h);
        int ans;
        ans = bfs();
        if (ans == 0x3f3f3f3f + 1)
            cout << 0 << endl;
        else
            cout << ans << endl;
    }
    return 0;
}

A计划

 可怜的公主在一次次被魔王掳走一次次被骑士们救回来之后,而今,不幸的她再一次面临生命的考验。魔王已经发出消息说将在T时刻吃掉公主,因为他听信谣言说吃公主的肉也能长生不老。年迈的国王正是心急如焚,告招天下勇士来拯救公主。不过公主早已习以为常,她深信智勇的骑士LJ肯定能将她救出。
现据密探所报,公主被关在一个两层的迷宫里,迷宫的入口是S(0,0,0),公主的位置用P表示,时空传输机用#表示,墙用*表示,平地用.表示。骑士们一进入时空传输机就会被转到另一层的相对位置,但如果被转到的位置是墙的话,那骑士们就会被撞死。骑士们在一层中只能前后左右移动,每移动一格花1时刻。层间的移动只能通过时空传输机,且不需要任何时间。 

Input
输入的第一行C表示共有C个测试数据,每个测试数据的前一行有三个整数N,M,T。 N,M迷宫的大小NM(1 <= N,M <=10)。T如上所意。接下去的前NM表示迷宫的第一层的布置情况,后N*M表示迷宫第二层的布置情况。
Output
如果骑士们能够在T时刻能找到公主就输出“YES”,否则输出“NO”。
Sample Input

1
5 5 14
S*#*.
.#...
.....
****.
...#.

..*.P
#.*..
***..
...*.
*.#..

Sample Output

YES

题解:相当于在三维上bfs

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;
const int maxn = 12;
string s[2][maxn];

struct node {
    int z;//在第0层还是第1层
    int x, y;//坐标
    int t;//时间
    node(int z, int x, int y, int t) : z(z), x(x), y(y), t(t) {}
};

int n, m, l;
int si, sj, sk, ei, ej, ek;
bool vis[2][maxn][maxn];

bool judge(int x, int y, int z) {
    return x >= 0 && x < n && y >= 0 && y < m && s[z][x][y] != '*';
}

int d[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};

void bfs() {
    memset(vis, false, sizeof(vis));
    queue<node> Q;
    vis[sk][si][sj] = true;
    Q.push(node(sk, si, sj, 0));
    while (!Q.empty()) {
        node now = Q.front();
        Q.pop();
        int z = now.z, x = now.x, y = now.y, t = now.t;
        if (x == ei && y == ej && z == ek && t <= l) {
            cout << "YES" << endl;
            return;
        }

        if (s[z][x][y] == '#' && s[z ^ 1][x][y] != '*' && s[z ^ 1][x][y] != '#' && !vis[z ^ 1][x][y]) {
            vis[z ^ 1][x][y] = true;
            Q.push(node(z ^ 1, x, y, t));
        }
        if (s[z][x][y] != '#')
            for (int i = 0; i < 4; i++) {
                int dx = x + d[i][0], dy = y + d[i][1];
                if (!judge(dx, dy, z) || vis[z][dx][dy])
                    continue;
                vis[z][dx][dy] = true;
                Q.push(node(z, dx, dy, t + 1));
            }
    }
    cout << "NO" << endl;
}

int main(void) {
    int t;
    cin >> t;
    while (t--) {
        cin >> n >> m >> l;
        for (int i = 0; i < n; i++)
            cin >> s[0][i];
        for (int i = 0; i < n; i++)
            cin >> s[1][i];

        for (int k = 0; k < 2; k++)
            for (int i = 0; i < n; i++)
                for (int j = 0; j < m; j++) {
                    if (s[k][i][j] == 'S')
                        si = i, sj = j, sk = k;
                    if (s[k][i][j] == 'P')
                        ei = i, ej = j, ek = k;
                }
        bfs();
    }
    return 0;
}

Oil Deposits

 The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots. It then analyzes each plot separately, using sensing equipment to determine whether or not the plot contains oil. A plot containing oil is called a pocket. If two pockets are adjacent, then they are part of the same oil deposit. Oil deposits can be quite large and may contain numerous pockets. Your job is to determine how many different oil deposits are contained in a grid.

Input
The input file contains one or more grids. Each grid begins with a line containing m and n, the number of rows and columns in the grid, separated by a single space. If m = 0 it signals the end of the input; otherwise 1 <= m <= 100 and 1 <= n <= 100. Following this are m lines of n characters each (not counting the end-of-line characters). Each character corresponds to one plot, and is either *', representing the absence of oil, or@’, representing an oil pocket.
Output
For each grid, output the number of distinct oil deposits. Two different pockets are part of the same oil deposit if they are adjacent horizontally, vertically, or diagonally. An oil deposit will not contain more than 100 pockets.
Sample Input

1 1
*
3 5
*@*@*
**@**
*@*@*
1 8
@@****@*
5 5 
****@
*@@*@
*@**@
@@@*@
@@**@
0 0 

Sample Output

0
1
2
2

题意:九宫格内连续相同的@有多少

题解:对着一个@dfs周围8个

#include<iostream>
#include<queue>

using namespace std;

const int N = 1e2 + 10;

string s[N];
int dx[] = {0, 1, 0, -1, 1, 1, -1, -1};
int dy[] = {1, 0, -1, 0, -1, 1, -1, 1};
int n, m;

void dfs(int x, int y) {
    if (s[x][y] == '@') {
        s[x][y] = '*';
    }
    for (int i = 0; i < 8; i++) {
        if (n > x + dx[i] && m > y + dy[i] && x + dx[i] >= 0 && y + dy[i] >= 0 && s[x + dx[i]][y + dy[i]] == '@' ) {
            dfs(x + dx[i], y + dy[i]);
        }
    }
}

int main(void) {
    while (cin >> n >> m && n && m) {
        for (int i = 0; i < n; i++) {
            cin >> s[i];
        }
        int ans = 0;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++) {
                if (s[i][j] == '@') {
                    dfs(i, j);
                    ans++;
                }
            }
        cout << ans << endl;
    }
    return 0;
}

DNA sequence

 The twenty-first century is a biology-technology developing century. We know that a gene is made of DNA. The nucleotide bases from which DNA is built are A(adenine), C(cytosine), G(guanine), and T(thymine). Finding the longest common subsequence between DNA/Protein sequences is one of the basic problems in modern computational molecular biology. But this problem is a little different. Given several DNA sequences, you are asked to make a shortest sequence from them so that each of the given sequence is the subsequence of it.

For example, given "ACGT","ATGC","CGTT" and "CAGT", you can make a sequence in the following way. It is the shortest but may be not the only one.

Input
The first line is the test case number t. Then t test cases follow. In each case, the first line is an integer n ( 1<=n<=8 ) represents number of the DNA sequences. The following k lines contain the k sequences, one per line. Assuming that the length of any sequence is between 1 and 5.
Output
For each test case, print a line containing the length of the shortest sequence that can be made from these sequences.
Sample Input

1
4
ACGT
ATGC
CGTT
CAGT

Sample Output

8

意义:找配对的

题解:限制一下搜索的深度即可

#include <iostream>

using namespace std;
int n;
int ans;
string s[10];
int deep;
char DNA[4] = {'A', 'T', 'C', 'G'};

void dfs(int index, int len[]) {
    if (index > deep) return;
    int maxn = 0;
    for (int i = 0; i < n; i++) {
        maxn = max((int(s[i].size()) - len[i]), maxn);
    }
    if (maxn == 0) {
        ans = index;
        return;
    }
    if (index + maxn > deep) return;
    for (int i = 0; i < 4; i++) {
        int flag = 0;
        int pos[10];
        for (int j = 0; j < n; j++) {
            if (s[j][len[j]] == DNA[i]) {
                flag = 1;
                pos[j] = len[j] + 1;
            } else {
                pos[j] = len[j];
            }
        }
        if (flag) dfs(index + 1, pos);
        if (ans != -1) return;
    }
}

int main(void) {
    int t;
    cin >> t;
    while (t--) {
        cin >> n;
        deep = 0;
        for (int i = 0; i < n; i++) {
            cin >> s[i];
            deep = max(deep, int(s[i].size()));
        }
        ans = -1;
        int pos[10] = {0};
        while (true) {
            dfs(0, pos);
            if (ans != -1) break;
            deep++;
        }
        cout << ans << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值