codeforces 1072D Minimum path bfs+剪枝 好题
Posted mountaink
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了codeforces 1072D Minimum path bfs+剪枝 好题相关的知识,希望对你有一定的参考价值。
题目大意:
给出一幅n*n的字符,从1,1位置走到n,n,会得到一个字符串,你有k次机会改变某一个字符(变成a),求字典序最小的路径。
题解:
(先吐槽一句,cf 标签是dfs题????)
这道题又学到了,首先会发现,从原点出发,走x步,所有的情况都是在一条斜线上的,而再走一步就是下一条斜线。所以用两个队列进行bfs(把当前步和下一步要处理的字符分开)。
到了这里思路就明朗了,每次走的时候如果本身的map里是a就直接走,不是a就看k是否大于0,再看这个字符是不是比答案串里对应位置的字符小,这样bfs主体就搭建完成了。
但是优秀的bfs显然要考剪枝(Orz)。
首先是一个保证正确性的剪枝,由于我们会更新某一个位子的字符,(c -> b -> a),但是修改的过程中前面那些并不是最优状态也被更新了,会导致答案错误,所以我采取的方法是记录每一个状态的字符,和答案串比较,是否一样,如果不一样,则代表答案串不是由这个状态变来的,continue掉。
其次是一个会影响时间的剪枝,由于到一个位子的k有很多种情况,显然我们应该保存k最大的那种情况,而k比较小的那些情况其实是冗余的,严重超时,所以我们每次更新答案串的时候,还应该更新一下 保证答案最优的情况下走到每个位子最大的k是多少。当某一个状态front出来的时候,先比较是否k是最大(最优)的,如果不是,也continue。
不过还有一个剪枝,应该是k>=2*n-1就可以直接输出aaaaa了,但是看时间似乎没必要。两个优先队列就用 f^1的方法就可以变化了。
//#pragma comment(linker,"/STACK:102400000,102400000") #include<cstdio> #include<algorithm> #include<iostream> #include<vector> #include<map> #include<set> #include<cstring> #include<cmath> #include<queue> #include<stack> #include<stdlib.h> //#include<unordered_map> #define lson l,mid,rt<<1 #define rson mid+1,r,(rt<<1)|1 #define CLR(a,b) memset(a,b,sizeof(a)) #define mkp(a,b) make_pair(a,b) typedef long long ll; using namespace std; inline int read(){ int x=0,f=1; char ch=getchar();while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f;} const int maxn=1e6+10; struct node{ int x,y,step; char pre; friend bool operator<(const node &a,const node &b) { return a.step<b.step; } }; char ans[4010],mp[2010][2010]; int mk[2010][2010]; int pos,n,k; queue<node>q[2]; int fx[2][2]={{0,1},{1,0}}; inline bool check(node &s) { if(s.x>n||s.y>n)return false; if(mp[s.x][s.y]==‘a‘){ ans[pos]=‘a‘; s.pre=‘a‘; return true; } if(s.step>0){ s.pre=‘a‘; ans[pos]=‘a‘; //printf("ans[%d]:%c ",pos,ans[pos]); s.step--; return true; } if(ans[pos]>=mp[s.x][s.y]){ ans[pos]=mp[s.x][s.y]; s.pre=ans[pos]; return true; } return false; } inline void bfs() { int f=0; while(!q[f].empty()) { node s=q[f].front(); q[f].pop(); if(s.x==s.y&&s.x==n)continue; if(s.pre==ans[pos-1]&&mk[s.x][s.y]==s.step){ for(int i=0;i<2;i++){ node ed=s; ed.x+=fx[i][0]; ed.y+=fx[i][1]; if(check(ed)){ if(ed.step>mk[ed.x][ed.y]){ mk[ed.x][ed.y]=ed.step; q[f^1].push(ed); } } } } if(q[f].empty()){ f=f^1; pos++; ans[pos]=(char)(‘z‘+1); } } } int main(){ cin>>n>>k; CLR(mk,-1); for(int i=1;i<=n;i++) { scanf("%s",mp[i]+1); } if(mp[1][1]!=‘a‘&&k>0){ k--; mp[1][1]=‘a‘; } ans[++pos]=mp[1][1]; pos++; ans[pos]=‘z‘+1; mk[1][1]=k; q[0].push({1,1,k,ans[pos-1]}); bfs(); for(int i=1;i<pos;i++) { printf("%c",ans[i]); } }
以上是关于codeforces 1072D Minimum path bfs+剪枝 好题的主要内容,如果未能解决你的问题,请参考以下文章