• 算法刷题day31


    引言

    这几天开始在 d e v c p p devcpp devcpp 上编写代码了,然后复制代码到 O J OJ OJ 上去测评,然后就是非常的不适应,代码环境、背景颜色、编译选项的一些设置啥的都很不好,而且也错的很多,主要是一些低级错误,所以说细节还是不到位,因为蓝桥杯是以最后一次提交为准,而且也不会给你任何反馈,所以说自己得提前适应这个环境和比赛规则,加油!


    一、奶牛选美

    标签:BFS

    思路:题目要求从一个斑点到另一个斑点地最短距离,由于 N ≤ 50 N \leq 50 N50 ,所以我们可以直接枚举一块斑点中的所有的点,看最小的碰到斑点地最短距离是多少。具体做法,我是先枚举了一块斑点,在 s t st st 数组中标记了,然后遍历这块斑点的所有点,取第一次碰到另一块斑点(最短距离)的最小值即可。具体细节可以见代码。

    题目描述:

    听说最近两斑点的奶牛最受欢迎,约翰立即购进了一批两斑点牛。
    
    不幸的是,时尚潮流往往变化很快,当前最受欢迎的牛变成了一斑点牛。
    
    约翰希望通过给每头奶牛涂色,使得它们身上的两个斑点能够合为一个斑点,让它们能够更加时尚。
    
    牛皮可用一个 N×M 的字符矩阵来表示,如下所示:
    
    ................
    ..XXXX....XXX...
    ...XXXX....XX...
    .XXXX......XXX..
    ........XXXXX...
    .........XXX....
    其中,X 表示斑点部分。
    
    如果两个 X 在垂直或水平方向上相邻(对角相邻不算在内),则它们属于同一个斑点,由此看出上图中恰好有两个斑点。
    
    约翰牛群里所有的牛都有两个斑点。
    
    约翰希望通过使用油漆给奶牛尽可能少的区域内涂色,将两个斑点合为一个。
    
    在上面的例子中,他只需要给三个 . 区域内涂色即可(新涂色区域用 ∗ 表示):
    
    ................
    ..XXXX....XXX...
    ...XXXX*...XX...
    .XXXX..**..XXX..
    ........XXXXX...
    .........XXX....
    请帮助约翰确定,为了使两个斑点合为一个,他需要涂色区域的最少数量。
    
    输入格式
    第一行包含两个整数 N 和 M。
    
    接下来 N 行,每行包含一个长度为 M 的由 X 和 . 构成的字符串,用来表示描述牛皮图案的字符矩阵。
    
    输出格式
    输出需要涂色区域的最少数量。
    
    数据范围
    1≤N,M≤50
    输入样例:
    6 16
    ................
    ..XXXX....XXX...
    ...XXXX....XX...
    .XXXX......XXX..
    ........XXXXX...
    .........XXX....
    输出样例:
    3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    示例代码:

    #include 
    
    using namespace std;
    
    typedef long long LL;
    typedef pair<int,int> PII;
    
    const int N = 100;
    
    int n, m;
    char g[N][N];
    bool st[N][N];
    int dist[N][N];
    
    int dir[4][2] = {0,1,0,-1,1,0,-1,0};
    
    void bfs1(PII S)
    {
    	st[S.first][S.second] = true;
    	
    	queue<PII> q; q.push({S.first, S.second});
    	while(q.size())
    	{
    		auto t = q.front(); q.pop();
    		
    		for(int i = 0; i < 4; ++i)
    		{
    			int x = t.first + dir[i][0];
    			int y = t.second + dir[i][1];
    			if(x < 0 || x >= n || y < 0 || y >= m) continue;
    			if(st[x][y] || g[x][y] == '.') continue;
    			
    			st[x][y] = true;
    			q.push({x,y});
    		} 
    	}
    }
    
    int bfs2(PII S)
    {
    	memset(dist, -1, sizeof dist);
    	dist[S.first][S.second] = 0;
    	
    	queue<PII> q; q.push({S.first, S.second});
    	while(q.size())
    	{
    		auto t = q.front(); q.pop();
    		
    		for(int i = 0; i < 4; ++i)
    		{
    			int x = t.first + dir[i][0];
    			int y = t.second + dir[i][1];
    			if(x < 0 || x >= n || y < 0 || y >= m) continue;
    			if(dist[x][y] != -1 || st[x][y]) continue;
    			
    			dist[x][y] = dist[t.first][t.second] + 1;
    			if(g[x][y] == 'X') return dist[x][y];
    			q.push({x,y});
    		} 
    	}
    	
    	return 1e9;
    }
    
    int main()
    {
    	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    	
    	cin >> n >> m;
    	for(int i = 0; i < n; ++i) cin >> g[i];
    
    	for(int i = 0; i < n; ++i)
    	{
    		bool flag = false;
    		for(int j = 0; j < m; ++j)
    		{
    			if(g[i][j] == 'X')
    			{
    				bfs1({i,j});
    				flag = true; break;
    			}
    		}
    		if(flag) break;
    	}
    	
    	
    	int res = 1e9;
    	for(int i = 0; i < n; ++i)
    	{
    		for(int j = 0; j < m; ++j)
    		{
    			if(st[i][j])
    			{
    				res = min(res, bfs2({i,j}));
    			}
    		}
    	}
    	
    	cout << res - 1 << endl;
    	
    	return 0;	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102

    二、树的重心

    标签:DFS

    思路:题目要求找到树的重心的那个值,也就是删掉该点后的连通块中的最大值最小。那么我们可以一一枚举所有的点,然后找到连通块最大值最小的即可。我们用递归来做, d f s ( u ) dfs(u) dfs(u) 返回的是包括结点 u u u 在内的所有孩子的总和。那么我们先是遍历每一个孩子,递归找出他们的连通块,并且因为是从根结点开始递归的,对于该结点以上的结点,我们可以记录一个 s u m sum sum ,最后拿总和减去再加上所有孩子的连通块,就可以求出删除该结点的每一个连通块的数量,取最小值即可。更多细节见代码。

    题目描述:

    给定一颗树,树中包含 n 个结点(编号 1∼n)和 n−1 条无向边。
    
    请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。
    
    重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。
    
    输入格式
    第一行包含整数 n,表示树的结点数。
    
    接下来 n−1 行,每行包含两个整数 a 和 b,表示点 a 和点 b 之间存在一条边。
    
    输出格式
    输出一个整数 m,表示将重心删除后,剩余各个连通块中点数的最大值。
    
    数据范围
    1≤n≤105
    输入样例
    9
    1 2
    1 7
    1 4
    2 8
    2 5
    4 3
    3 9
    4 6
    输出样例:
    4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    示例代码:

    #include 
    
    using namespace std;
    
    typedef long long LL;
    typedef pair<int,int> PII;
    
    const int N = 1e5+10, M = N * 2;
    
    int n;
    int h[N], e[M], ne[M], idx;
    bool st[N];
    int ans = 2e9;
    
    void add(int a, int b)
    {
    	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
    }
    
    int dfs(int u)
    {
    	st[u] = true;
    	
    	int sum = 1, size = 0;
    	for(int i = h[u]; i != -1; i = ne[i])
    	{
    		int j = e[i];
    		if(st[j]) continue;
    		
    		int t = dfs(j);
    		sum += t;
    		size = max(size, t);
    	}
    	
    	size = max(size, n - sum);
    	ans = min(ans, size);
    	
    	return sum; 
    }
    
    int main()
    {
    	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    	
    	memset(h, -1, sizeof h);
    	cin >> n;
    	for(int i = 0; i < n; ++i)
    	{
    		int a, b;
    		cin >> a >> b;
    		add(a,b), add(b,a);
    	}
    	
    	dfs(1);
    	
    	cout << ans << endl;
    	
    	return 0;	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    三、大臣的旅费

    标签:树的直径、BFS

    思路:要求花费最多,也就是求走的路最长, 然后根据数学关系就可以算出来了。求路最长,也就是求树的直径,公式就是先任意选取一个点,找到最远的点,然后从这个点开始再求一遍,这时最远的距离,就是它了。最远点我的可以用 B F S BFS BFS 做,在里面判断一下就行了,因为该图的边的权值都是正的且相等,所以能用 B F S BFS BFS

    题目描述:

    很久以前,T 王国空前繁荣。
    
    为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。
    
    为节省经费,T 国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。
    
    同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。
    
    J 是 T 国重要大臣,他巡查于各大城市之间,体察民情。
    
    所以,从一个城市马不停蹄地到另一个城市成了 J 最常做的事情。
    
    他有一个钱袋,用于存放往来城市间的路费。
    
    聪明的 J 发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关。
    
    具体来说,一段连续的旅途里,第 1 千米的花费为 11,第 2 千米的花费为 12,第 3 千米的花费为 13,…,第 x 千米的花费为 x+10。
    
    也就是说,如果一段旅途的总长度为 1 千米,则刚好需要花费 11,如果一段旅途的总长度为 2 千米,则第 1 千米花费 11,第 
    2 千米花费 12,一共需要花费 11+12=23。
    
    J 大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?
    
    输入格式
    输入的第一行包含一个整数 n,表示包括首都在内的 T 王国的城市数。
    
    城市从 1 开始依次编号,1 号城市为首都。
    
    接下来 n−1 行,描述 T 国的高速路(T 国的高速路一定是 n−1 条)。
    
    每行三个整数 Pi,Qi,Di,表示城市 Pi 和城市 Qi 之间有一条双向高速路,长度为 Di 千米。
    
    输出格式
    输出一个整数,表示大臣 J 最多花费的路费是多少。
    
    数据范围
    1≤n≤105,1≤Pi,Qi≤n,1≤Di≤1000
    输入样例:
    5
    1 2 2
    1 3 1
    2 4 5
    2 5 4
    输出样例:
    135
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    示例代码:

    #include 
    
    using namespace std;
    
    typedef long long LL;
    typedef pair<int,int> PII;
    
    const int N = 1e5+10, M = N * 2, INF = 0x3f3f3f3f;
    
    int n, m;
    int h[N], e[M], w[M], ne[M], idx;
    int dist[N];
    int maxv = -1, maxid = 0;
    
    void add(int a, int b, int c)
    {
    	e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
    }
    
    void bfs(int S)
    {
    	memset(dist, -1, sizeof dist);
    	dist[S] = 0;
    	
    	queue<int> q; q.push(S);
    	while(q.size())
    	{
    		int t = q.front(); q.pop();
    		
    		for(int i = h[t]; i != -1; i = ne[i])
    		{
    			int j = e[i];
    			if(dist[j] != -1) continue;
    			
    			dist[j] = dist[t] + w[i];
    			if(dist[j] > maxv) maxv = dist[j], maxid = j;
    			q.push(j);
    		}
    	}
    }
    
    int main()
    {
    	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    	
    	memset(h,-1,sizeof h);
    	cin >> n;
    	for(int i = 0; i < n - 1; ++i)
    	{
    		int a, b, c; cin >> a >> b >> c;
    		add(a,b,c), add(b,a,c);
    	}
    	
    	bfs(1);
    	
    	bfs(maxid);
    	
    	LL res = 10ll * maxv + (1ll + maxv) * maxv / 2;
    	cout << res << endl;
    	
    	return 0;	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    四、迷宫

    标签:BFS

    思路:就是一个 B F S BFS BFS 模板题,没啥说的,值得注意的是,这道题的起点或者终点也有可能走不了,所以需要特判一下。

    题目描述:

    一天Extense在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由 n∗n 的格点组成,每个格点只有2种状态,.和#,前者表示可以通行后者表示不能通行。
    
    同时当Extense处在某个格点时,他只能移动到东南西北(或者说上下左右)四个方向之一的相邻格点上,Extense想要从点A走到
    点B,问在不走出迷宫的情况下能不能办到。
    
    如果起点或者终点有一个不能通行(为#),则看成无法办到。
    
    注意:A、B不一定是两个不同的点。
    
    输入格式
    第1行是测试数据的组数 k,后面跟着 k 组输入。
    
    每组测试数据的第1行是一个正整数 n,表示迷宫的规模是 n∗n 的。
    
    接下来是一个 n∗n 的矩阵,矩阵中的元素为.或者#。
    
    再接下来一行是 4 个整数 ha,la,hb,lb,描述 A 处在第 ha 行, 第 la 列,B 处在第 hb 行, 第 lb 列。
    
    注意到 ha,la,hb,lb 全部是从 0 开始计数的。
    
    输出格式
    k行,每行输出对应一个输入。
    
    能办到则输出“YES”,否则输出“NO”。
    
    数据范围
    1≤n≤100
    输入样例:
    2
    3
    .##
    ..#
    #..
    0 0 2 2
    5
    .....
    ###.#
    ..#..
    ###..
    ...#.
    0 0 4 0
    输出样例:
    YES
    NO
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    示例代码:

    #include 
    
    using namespace std;
    
    typedef long long LL;
    typedef pair<int,int> PII;
    
    const int N = 110;
    
    int T;
    int n, m;
    char g[N][N];
    bool st[N][N];
    PII S, E;
    
    int dir[4][2] = {0,1,0,-1,1,0,-1,0};
    
    bool bfs()
    {
    	if(g[S.first][S.second] == '#' || g[E.first][E.second] == '#') return false;
    	memset(st, 0, sizeof st);
    	st[S.first][S.second] = true;
    	
    	queue<PII> q; q.push(S);
    	while(q.size())
    	{
    		auto t = q.front(); q.pop();
    		
    		for(int i = 0; i < 4; ++i)
    		{
    			int x = t.first + dir[i][0];
    			int y = t.second + dir[i][1];
    			if(x < 0 || x >= n || y < 0 || y >= n) continue;
    			if(st[x][y] || g[x][y] == '#') continue;
    			
    			st[x][y] = true;
    			q.push({x,y});
    		}
    	}
    	return st[E.first][E.second];
    }
    
    int main()
    {
    	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    	
    	cin >> T;
    	while(T--)
    	{
    		cin >> n;
    		for(int i = 0; i < n; ++i) cin >> g[i];
    		cin >> S.first >> S.second >> E.first >> E.second;
    		
    		if(bfs()) puts("YES");
    		else puts("NO");
    	}
    	
    	return 0;	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
  • 相关阅读:
    Linux基本命令
    GET和POST的区别
    软件测试面试题【2023最新合集】
    多线程开发中,多用消息传递,少用锁
    list容器模拟实现【c++】
    idea的插件这么赞,你竟不知道?
    什么是Git引用和分支?
    k8s强制删除pod、svc、namespace(Terminating)
    Coursera Algorithm Ⅱ week1 WordNet
    知识直播的“顶流”,正在被复制
  • 原文地址:https://blog.csdn.net/weixin_60033897/article/details/136757711