【前言】今天继续洛谷闯关,感觉小白进化为小灰啦! 继上次做了一道迷宫题之后,对迷宫题有了执念,这几天可能闯关各种类型的迷宫题哈哈哈哈哈哈哈
P1605 迷宫
题目背景
给定一个N*M方格的迷宫,迷宫里有T处障碍,障碍处不可通过。给定起点坐标和终点坐标,问: 每个方格最多经过1次,有多少种从起点坐标到终点坐标的方案。在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。
笔记
- 读题可知,用深度优先算法。以下是我自用的深度优先算法模板(伪代码):
const int N=10; //根据题目条件确定数组大小
int nums[N]; // 原数组 可有可无
int result[N]; //保存最后结果 可有可无
int used[N]={0}; // 是否被用过 必须有
void dfs(int count){
// 出口
if(count==4){
根据题目要求,对result处理
}
//入口
for(int i=0;i<4;i++){ //假设结果为4个子项
if(used[i]==0){ //如果i未遍历,置1
used[i] = 1;
result[count]=i+1; // 结果下标为 count,count从1->4
dfs(count+1); //递归
used[i]=0; //恢复,以便下次使用
}
}
}
int main(){
dfs(0);
return 0;
}
//(感谢黄焖鸡学长大力支持)
- 一定要先确定好数据结构,比如这道题,障碍结点完全可以用二维数组标记出来,单独写一个vector反而更复杂
- 利用dx,dy数组打表的思想,虽阅读性减弱,但大大简化了代码量,是个好操作
/*
输入格式
第一行N、M和T,N为行,M为列,T为障碍总数。第二行起点坐标SX,SY,终点坐标FX,FY。接下来T行,每行为障碍点的坐标。
输出格式
给定起点坐标和终点坐标,问每个方格最多经过1次,从起点坐标到终点坐标的方案总数。
*/
#include<iostream>
#include<vector>
#include<utility>
using namespace std;
int n,m,t,sx,sy,fx,fy,ans=0;
int used[6][6]={0}; //保存 用过 的节点 和障碍节点,我直接写一起了,其实写成两个更容易理解
vector<pair<int,int> > v_r; //保存 结果路径,这道题没问,大可不必写
pair<int,int> t_p; //临时 pair
int dx[4]={-1,0,1,0}; // 打表 新学的,原本我是把四个循环都写出来了
int dy[4]={0,-1,0,1};
bool isinArea(int x,int y){ //判断是否出界,写进去太乱了才写出来,无所谓
if(x>0&&x<=n&&y>0&&y<=m)return true;
return false;
}
void dfs(int x,int y){
// flag=true; 这部分是之前的版本,大可不必
//出口1 遇障碍
// for(int i=0;i<v_h.size();i++){
// if(x==v_h[i].first&&y==v_h[i].second){
// flag=false;
// break;
// }
// }
// if(!flag) break;
//出口
if(x==fx&&y==fy) {
ans++;
// int k=v_r.size()-1; //为了让自己看看结果,相当于手动debug,大可不必
// cout<<"<"<<v_r[k].first<<","<<v_r[k].second<<">"<<"ans: "<<ans<<endl;
return; //返回,继续
}
//第一次
used[x][y]=1;
for(int i=0;i<4;i++){
if(used[x+dx[i]][y+dy[i]]==0&&isinArea(x+dx[i],y+dy[i])){
used[x+dx[i]][y+dy[i]]=1;
t_p.first=x+dx[i]; t_p.second=y+dy[i];
v_r.push_back(t_p);
dfs(x+dx[i],y+dy[i]);
used[x+dx[i]][y+dy[i]]=0;
}
}
used[x][y]=0;
}
int main(){
while(cin>>n>>m>>t){
cin>>sx>>sy>>fx>>fy;
int x,y;
for(int i=0;i<t;i++){
cin>>x>>y;
used[x][y]=1;
}
dfs(sx,sy);
cout<<ans<<endl;
}
return 0;
}
P1098 字符串的展开
题目描述
在初赛普及组的“阅读程序写结果”的问题中,我们曾给出一个字符串展开的例子:如果在输入的字符串中,含有类似于“d-h”或者“4-8”的字串,我们就把它当作一种简写,输出时,用连续递增的字母或数字串替代其中的减号,即,将上面两个子串分别输出为“defgh”和“45678"。在本题中,我们通过增加一些参数的设置,使字符串的展开更为灵活。具体约定如下:
(1) 遇到下面的情况需要做字符串的展开:在输入的字符串中,出现了减号“-”,减号两侧同为小写字母或同为数字,且按照ASCII码的顺序,减号右边的字符严格大于左边的字符。
(2) 参数p1:展开方式。p1=1时,对于字母子串,填充小写字母;p1=2时,对于字母子串,填充大写字母。这两种情况下数字子串的填充方式相同。p1=3时,不论是字母子串还是数字字串,都用与要填充的字母个数相同的星号“*”来填充。
(3) 参数p2:填充字符的重复个数。p2=k表示同一个字符要连续填充k个。例如,当p2=3时,子串“d-h”应扩展为“deeefffgggh”。减号两边的字符不变。
(4) 参数p3:是否改为逆序:p3=1表示维持原来顺序,p3=2表示采用逆序输出,注意这时候仍然不包括减号两端的字符。例如p1=1、p2=2、p3=2时,子串“d-h”应扩展为“dggffeeh”。
(5) 如果减号右边的字符恰好是左边字符的后继,只删除中间的减号,例如:“d-e”应输出为“de”,“3-4”应输出为“34”。如果减号右边的字符按照ASCII码的顺序小于或等于左边字符,输出时,要保留中间的减号,例如:“d-d”应输出为“d-d”,“3-1”应输出为“3-1”。
笔记
- 这道题可不用改变原字符串,直接输出,这样就更容易了。
- p1,p2,p3 有多种组合情况时,要考虑怎么能减少比较的次数,先判断谁后判断谁。此题p1 和填充内容有关,p2和重复输出有关,p3表示是否反着输出,而是否 反着输出 表现在输出的循环上,p1,p2写在循环里。先比较p1,确定输出的内容,之后输出p2次
- 遇到‘-’,要么输出‘-’,要么输出隐藏 的字母或数字。
- 如果p1==1时,不管是字母还是数字
#include<iostream>
#include <string>
using namespace std;
const int mns='A'-'a'; //大小写的 差值
int p1,p2,p3;
char low,high,temp,j;
int main(){
while(cin>>p1>>p2>>p3){
string s;
cin>>s;
for(int i=0;i<s.size();i++){
low=s[i-1];high=s[i+1];
if((s[i]=='-')&&(low<high)&&((low>='0'&&high<='9')||(low>='a'&&high<='z'))){
for(p3==1?j=low+1:j=high-1;p3==1?j<high:j>low;p3==1?j++:j--){
if(p1==1) temp=j;
else if(p1==2) temp=j>='a'?j+mns:j;
else temp='*';
for(int k=0;k<p2;k++) // 只要确定数量!用for
cout<<temp;
}
}
else cout<<s[i];
}
}
return 0;
}