1、按下方向键时跳到下一个不同的字符,也就意味着光标可以“传送”。
2、最后要打印一个回车,也就是“*”号。
3、选择也是一次操作。
4、可能有多组数据。
5、因为同样的字母会重复出现,所以如果BFS一个接一个的找时,第一个找到的未必是全局最优的,如图(假设我们要打印"\(AB\)"):
蓝色框是一个一个字符去BFS,先找到一个,再找下一个,(每个箭头算一步,因为光标会且只会移动到该方向下一个不同的字符),红色是正确走法。
思路:
1、先预处理每个点可以到的地方(最多4个),存入f数组。
2、list数组保存每一个BFS到的点的x、y坐标,所用的步数(dep)及从出发点到这个点的路径中已打印的字符数(find)。
3、dep数组表示地图上每一个点作为一条路径的终点可以打印多少字符。
4、(重点)如果从出发点到当前的点再到另一个点比出发点到那个点的原路径所打印的字符更多,那么更新那个点的find和dep值,也就是说以这个点为终点,有另一条路径,并且路径上打印的字符更多(类似SPFA)。反则不更新,因为已经被遍历过的点所用步数肯定比当前的点的步数少。
5、如果当前点是下一个要打印的点,就find++,表示去寻找下一个字符。
6、找到最后一个字符后输出步数并return 0;
(因为我太弱了不会用队列,只好有循环数组)
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int dx[4]={-1,0,1,0};//四个方向 int dy[4]={0,-1,0,1};//四个方向 char s[110000],map[2100][2100]; int r,c,xx,yy,len,head,tail,dep[2100][2100]; struct node { int x,y,dep,find;//x,y是坐标,dep表示当前所用步数,find表示以当前点为终点的路径中已打印的字符数 }list[1600000]; struct nodee { int x[5],y[5],len;//x,y数组表示可以去到的位置,len表示可前往的点的数量 nodee() { len=0; } }f[2100][2100]; void chuli()//预处理每个点能去到的地方,记录在f数组里 { for(int i=1;i<=r;i++) for(int j=1;j<=c;j++) for(int k=0;k<=3;k++) { xx=i; yy=j; while(map[i][j]==map[xx+dx[k]][yy+dy[k]]&& xx+dx[k]&&yy+dy[k])//一直循环直到下一个点是合法的或者到达边界 { xx+=dx[k]; yy+=dy[k]; } if(map[i][j]!=map[xx+dx[k]][yy+dy[k]]&& xx+dx[k]&&yy+dy[k])//如果下一个是点是合法的,就加入f数组 { f[i][j].len++; f[i][j].x[f[i][j].len]=xx+dx[k]; f[i][j].y[f[i][j].len]=yy+dy[k]; } } return ; } int main() { while(scanf("%d%d",&r,&c)!=EOF)//多组数据 { memset(f,0,sizeof(f)); memset(dep,-1,sizeof(dep)); memset(list,0,sizeof(list)); memset(map,' ',sizeof(map));//初始化 for(int i=1;i<=r;i++) scanf("%s",map[i]+1); scanf("%s",s+1); len=strlen(s+1); s[len+1]='*'; len++;//最后要打印一个回车,也就是“*”号 chuli();//预处理 xx=yy=1; head=1; tail=2; list[1].x=xx; list[1].y=yy; list[1].dep=0; list[1].find=0; while(head!=tail) { if(map[list[head].x][list[head].y]==s[list[head].find+1])//如果当前的点是下一个要打印的字符,就重新加入队列同时把已打字符数加1 { list[tail]=list[head]; list[tail].dep++; list[tail].find++; if(list[tail].find==len)//如果所有数都打印了,就输出并结束。 { printf("%d\n",list[head].dep+1); break; } tail++; } for(int k=1;k<=f[list[head].x][list[head].y].len;k++)//逐个遍历当前点可以去到的其他点 { xx=f[list[head].x][list[head].y].x[k]; yy=f[list[head].x][list[head].y].y[k]; if(dep[xx][yy]<list[head].find)//这个dep数组与结构体中的dep不同,dep数组表示地图中每一个点作为终点,路径上最多能打印的字符数,如果这个点作为终点有可打印更多的字符,就更新它并加入队列去更新更多的点 { list[tail].x=xx; list[tail].y=yy; list[tail].dep=list[head].dep+1; list[tail].find=list[head].find; dep[xx][yy]=list[head].find; tail++; if(tail>1500000) tail=1; } } head++; } } return 0; }不要试图抄袭、复制或是删掉注释后提交代码,就算我不把你打死,你也AC不了的。(因为我修改了一点小东西,嘿嘿嘿)
转载于:https://www.cnblogs.com/wangjieyu/p/10011576.html
相关资源:JAVA上百实例源码以及开源项目