题目传送门

题目大意:

  给出一幅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\n",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]);
    }
}
View Code

相关文章: