【算法练习】算法练习精选:从 Phone numbers 到 Decrease,覆盖字符串、模拟、图论思维题

🔭 个人主页: 散峰而望

《C语言:从基础到进阶》《编程工具的下载和使用》《C语言刷题》

《C++》《算法竞赛从入门到获奖》《人工智能》《AI Agent》
愿为出海月,不做归山云


🎬博主简介

【算法练习】算法练习精选:从 Phone numbers 到 Decrease,覆盖字符串、模拟、图论思维题

  • 前言
  • [1. CF25B Phone numbers](#1. CF25B Phone numbers)
  • [2. zzc 种田](#2. zzc 种田)
  • [3. 信息传递](#3. 信息传递)
  • [4. Decrease](#4. Decrease)
  • 结语

前言

算法练习是编程学习路上不可或缺的一环。本次精选的四道题目,分别涉及字符串处理、数学思维、图论建模与差分数组技巧,难度由浅入深,覆盖了竞赛中常见的经典题型。每道题都配有详细的算法原理分析与完整可运行的参考代码,希望能帮助读者在实战中巩固基础、拓宽思路。话不多说,让我们开始今天的算法之旅吧!

1. CF25B Phone numbers

CF25B

算法原理:

利用分类讨论

判断一下 n 的奇偶:

  • 如果是偶数,直接两个两个分开;
  • 如果是奇数,两个两个分开,最后一个分三个。

参考代码:

cpp 复制代码
#include <iostream>

using namespace std;

int main()
{
	int n; string s;
	cin >> n >> s;
	
	if(n % 2) //奇数
	{
		for(int i = 0; i < n; i++)
		{
			cout << s[i];
			if(i % 2 && i < n - 3) cout << '-';
		}
	} 
	
	else //偶数
	{
		for(int i = 0; i < n; i++)
		{
			cout << s[i];
			if(i % 2 && i < n - 2) cout << '-';
		}
	} 
	
	return 0;
 } 

2. zzc 种田

zzc 种田

算法原理:

数学

每次都切出边长为 min(x, y) 的正方形,切完后,计算出新的 x 和 y ,然后继续切。

cpp 复制代码
#include <iostream>

using namespace std;

typedef long long LL;

int main()
{
	LL x, y; cin >> x >> y;
	
	LL sum = 0;
	while(x && y)
	{
		//假设 x > y,求出最小正方形有几个 
		LL cnt = x / y; 
		sum += cnt * y * 4;
		//剩余的矩形的长 
		x %= y;
		//确保矩形长大于宽 
		swap(x, y);
	}
	
	cout << sum << endl;
	
	return 0;
}

3. 信息传递

信息传递

算法原理:

拓扑排序 + DFS 计数

  1. 拓扑排序的过程可以把除环的部分的点打上标记;
  2. 对没有打上标记的环进行一次 DFS,统计一下大小。

参考代码:

cpp 复制代码
#include <iostream>
#include <queue>

using namespace std;

const int N = 2e5 + 10;

int n;
int ne[N]; //记录T
int in[N]; //记录入度信息
bool st[N]; //判断是否被标记
int cnt; 

void dfs(int i)
{
	cnt++;
	st[i] = true;
	int b = ne[i];
	if(!st[b]) dfs(b);
}

int main()
{
	cin >> n;
	for(int i = 1; i <= n; i++)
	{
		cin >> ne[i];
		in[ne[i]]++;
	}
	
	//1.利用拓扑排序把除环的部分的点打上标记
	queue<int> q; 
	for(int i = 1; i <= n; i++)
	{
		if(in[i] == 0)
		    q.push(i);
	}
	
	while(q.size())
	{
		auto a = q.front(); q.pop();
		st[a] = true;
		
		int b = ne[a];
		in[b]--;
		if(in[b] == 0) q.push(b);
	}
	
	//2.利用dfs计算环的大小
	int ret = n;
	for(int i = 1; i <= n; i++)
	{
		if(!st[i])
		{
			//因为可能不止一个环,所以需要初始一下环的大小 
			cnt = 0;
			dfs(i);
			ret = min(cnt, ret);
		}
	} 
	
	cout << ret << endl;
	
	return 0;
} 

4. Decrease

Decrease

算法原理:

根据连续子矩阵加 1 减 1 ,我们可以考虑二维差分

为了方便进行「区间修改」操作,我们创建原矩阵的「差分矩阵」,记为 f f f。如果让原矩阵的「所有元素」都变成 0,相应的差分矩阵中的「所有元素」也都会变成 0。问题就转化成了把 f f f 矩阵变成 0 的最小操作次数。对原矩阵进行「区间」操作对应差分矩阵中「点」的操作,因此在原矩阵中把一个边长为 k k k 的子矩阵修改成 0,对应差分矩阵中「四个点」的修改。

那么我们就可以枚举「差分矩阵」中的左上角 ( i , j ) (i,j) (i,j),其中 1 ≤ i , j ≤ ( n − k + 1 ) 1 \le i,j \le (n - k + 1) 1≤i,j≤(n−k+1),然后进行「区间修改」操作:

  • 如果 f i j fij fij 不等于 0,那我们就把这个区间变成 0,操作次数就是 a b s ( f i j ) abs(fij) abs(fij);
  • 如果 f i j fij fij 等于 0,无需操作。

当把差分矩阵中 1 , n − k + 1 1,n - k + 1 1,n−k+1 区间内的所有元素「都变成 0」之后,扫描整个差分矩阵:

  • 如果全变成 0,输出最小次数;
  • 如果存在不等于 0 的位置,说明不能把整个矩阵变成 0,输出 − 1 -1 −1。

参考代码:

cpp 复制代码
#include <iostream>
#include <cmath>

using namespace std;

typedef long long LL;

const int N = 5e3 + 10;
int n, m, k;
LL f[N][N]; // 差分

void insert(int x1, int y1, int x2, int y2, int k)
{
    f[x1][y1] += k;
    f[x1][y2 + 1] -= k;
    f[x2 + 1][y1] -= k;
    f[x2 + 1][y2 + 1] += k;
}

int main()
{
    cin >> n >> m >> k;
    for(int i = 1; i <= m; i++)
    {
        int x, y, z; cin >> x >> y >> z;
        insert(x, y, x, y, z);
    }
    
    LL ret = 0;
    for(int x1 = 1; x1 <= n - k + 1; x1++)
        for(int y1 = 1; y1 <= n - k + 1; y1++)
        {
            ret += abs(f[x1][y1]);
            int x2 = x1 + k - 1, y2 = y1 + k - 1;
            insert(x1, y1, x2, y2, -f[x1][y1]);
        }
        
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            if(f[i][j] != 0)
            {
                cout << -1 << endl;
                return 0;
            }
            
    cout << ret << endl;
    
    return 0;
}

结语

本次算法练习涵盖字符串、数学、图论与差分数组四类题型。分类讨论、贪心切割、拓扑找环、二维差分------每道题都锤炼了一种经典思维。算法无捷径,唯勤练与总结,方能游刃有余。

愿共渡重重浪,终见繁光远缀天

相关推荐
薇茗1 小时前
【C++】 基础语法篇
c++·c++基础语法
人道领域1 小时前
【LeetCode刷题日记】538.把二叉搜索树转换为累加树
java·开发语言·后端·算法·leetcode
并不喜欢吃鱼1 小时前
从零开始 C++----- 十二【C++ 数据结构】map/set 全解析:从使用到红黑树底层模拟实现
开发语言·数据结构·c++
不会C语言的男孩1 小时前
C++ Primer Plus 第17章:输入、输出和文件
开发语言·c++
Lsk_Smion1 小时前
力扣实训 _ [33].搜索旋转排序数组 _ [92].翻转链表Ⅱ
java·数据结构·算法
j_xxx404_1 小时前
Linux 线程同步硬核解析:从条件变量、阻塞队列到信号量环形队列
linux·运维·服务器·c++·人工智能·ai·中间件
MrZhao4001 小时前
多 Agent 协作与通信:MessageBus 最小实现
算法
Zhang~Ling1 小时前
二叉搜索树(BST)详解:插入、删除、查找与 Key/Value 实战场景
数据结构·c++·算法
8Qi81 小时前
LeetCode 76. 最小覆盖子串(Minimum Window Substring)
数据结构·算法·leetcode·滑动窗口·哈希表