《算法篇》--模拟算法

模拟算法介绍:

模拟算法是通过模拟实际情况来解决问题,一般容易理解但是实现起来比较复杂,有很多需要注意的细节,或者是一些所谓很“麻烦”的东西。模拟题一般不涉及太难的算法,一般就是由较多的简单但是不好处理的部分组成的,考察选手的细心程度和整体的逻辑思维。
一般为了使得模拟题写的逻辑清晰一些,经常会写比较多的小函数来帮助解题,例如int和string的相互转换、回文串的判断、日期的转换、各种特殊条件的判断等等。

实战才是硬道理,上栗子:

eg1 lanqiao OJ 545 扫雷

这道题就是一个典型的模拟题目:

问题模拟化,首先排雷找到雷,然后再扫描不是雷的点的四周

下面为解题代码,注释很详细

//eg1 lanqiao OJ 545 扫雷
#include<bits/stdc++.h>
using namespace std;
const int N=150;
//mp代表输入的,ans代表扫描后的数组; 
int mp[N][N],ans[N][N];
int m,n;
int main()
{
	ios::sync_with_stdio(0),cout.tie(0),cout.tie(0);
	//输入长宽吗m,n; 
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
	{
		//输入n行m列的方格图 
		cin>>mp[i][j];
	} 
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
	{
		//判断该点是不是雷;
		if(mp[i][j]==1)
		{
			ans[i][j]=9;
			continue;
		 } 
		//扫描周围八个点(这里扫描方式有一点特别,不清楚的可以自己画一个图来联想一下)
		for(int _i=max(0,i-1);_i<=min(n,i+1);++_i)
		for(int _j=max(0,j-1);_j<=min(m,j+1);++_j)
		{
			//判断该点是不是雷 
			if(mp[_i][_j]==1) 
			ans[i][j]++; 
		}
	} 
	//最后输出ans数组; 
	for(int i=1;i<=n;i++)
	{
	for(int j=1;j<=m;j++)
	{
		cout<<ans[i][j]<<' ';
	}
	cout<<endl;		
	}
	return 0;
}

接下来看第二个栗子:

eg2:lanqiao OJ 551 灌溉

这道题同样也是一道很典型的模拟题目:

原理上它和扫雷非常相似,但是结果处理上需要一点变化

代码如下:

//灌溉 花园//   留了一个小问题,关于边界 (已解决)
#include<bits/stdc++.h>
using namespace std;
const int N=120;
//把数组初始化为0 
int ma[N][N],ans[N][N];
int main()
{
	//定义花园大小 
	int m,n;
	cin>>m>>n;
	//t是定义的出水口数量 
	int t;
	cin>>t;
	//这一个for循环是把出水口定义为1,因为出水口本身就算是被灌溉的区域 
	for(int i=1;i<=t;i++)
	{
		int a,b;
		cin>>a>>b;
		ma[a][b]=1;
	}
	//k是定义的时间,代表放水k分钟 
	int k;
	cin>>k;
	//一个while循环,每分钟都要更新一次 
	while(k--)
	{
		for(int i=0;i<m;i++)
		for(int j=0;j<n;j++)
		{
			if(ma[i][j]==1)
			//出水口每一分钟都会向四个方向扩散 
			ans[i][j]=ans[i-1][j]=ans[i+1][j]=ans[i][j+1]=ans[i][j-1]=1;
		}
		//把ans复制到ma,进行下一分钟的循环 
		for(int i=0;i<m;i++)
		for(int j=0;j<n;j++)
		ma[i][j]=ans[i][j];
	}
	    //定义ant,代表被灌溉的数量 
	    int ant=0;
		for(int i=0;i<m;i++)
		for(int j=0;j<n;j++)
		{
			//如果ma=1,代表被灌溉,ant+1; 
		if(ma[i][j])
		ant++;	
		}
		//输出	
		cout<<ant;
	return 0;
}

eg3:lanqiao OJ 498 回文日期//模拟

这道题在蓝桥云里面被定义为难题,如果掌握这道题,模拟算法就算是正式入门了,下面看题:

这道题在蓝桥云里面被定义为难题,如果掌握这道题,模拟算法就算是正式入门了:

最开始我们介绍模拟算法时说到,,经常会写比较多的小函数来帮助解题,例如int和string的相互转换、回文串的判断、日期的转换、各种特殊条件的判断等等;而回文日期这道题可算是把模拟算法的特点体现的淋漓尽致,我们需要写很多个小函数去判断,这些小函数就是这道题的重点:

上代码;

//回文日期//模拟
#include<bits/stdc++.h>
using namespace std;
//第一个函数,将string转化为int 
int s_i(string s)
{
	int res=0;
	for(auto &i:s)
	{
		res=res*10+i-'0';
	}
	return res;
}
//第二个函数将int转化为string型 
string i_s(int a,int w)
{
	string res;
	while(a)
	{
		res+=(a%10)+'0';
		a=a/10;
	}
	while(res.length()<w)
	{
		res+='0';
	}
	reverse(res.begin(),res.end());
	return res;
}
//第三个函数判断年份是否为闰年 
bool ryear(int year)
{
	
	if((year%4==0&&year%100==0)||year%400==0)
	return true;
	else
	return false;
}
//第四个函数判断是否是正常年月日 
bool zcyear(int year,int mouth,int day)
{
      int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
      if(ryear(year))
      days[2]=29;
      return day<=days[mouth];
}
//第五个函数判断是否是回文年份 
bool huiwen(string s)
{
	for(int i=0;i<s.length()/2;i++)
	{
	if(s[i]!=s[s.length()-1-i])
	return false;
	}
	return true;
}
//第六个函数判断是否是特殊年份 
bool teshu(string s)
{
	if(!huiwen(s))
	return false;
	return s[0]==s[2]&&s[1]==s[3];
}
int main()
{
	string s;
	cin>>s;
	int ans1=0,ans2=0;
	int year=s_i(s.substr(0,4));
	int mouth=s_i(s.substr(4,2));
	int day=s_i(s.substr(6,2));
	for(int i=year;i<9999;i++)
	{
		for(int j=mouth;j<=12;j++)
		{
			if(i==year&&j<mouth)
			continue;
			for(int k=1;k<=31;k++)
			{
				if(j==mouth&&k<=day)
				continue;
				if(!zcyear(i,j,k))
				continue;	
				string s1=i_s(i,4)+i_s(j,2)+i_s(k,2);
				if(s1.length()>8)
				continue;
				if(!ans1&&huiwen(s1))
				{
					cout<<s1<<endl;
					ans1=1;
				}
				if(huiwen(s1)&&teshu(s1))
				{
					cout<<s1;
					return 0;
				}
			}
		}
	}
	return 0;
 }

看似代码很多,实际上我们只是运用了六个函数,然后再次基础上用逻辑把六个函数串联起来,理解之后是很简单的,但操作起来确实很麻烦;

本期模拟算法介绍到此为止,总结一下就是思路逻辑比较简单,但是解决回文日期这样的题目时往往会很麻烦.

  • 14
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值