CF1072 Div2D (Div1B)Minimum path

一个简单的dp

这题打比赛的时候用BFS实现被卡了内存很是难受,赛后十分钟改成dp写法就过了此题。

题面

D. Minimum path
time limit per test1.5 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
You are given a matrix of size n×n filled with lowercase English letters. You can change no more than k letters in this matrix.

Consider all paths from the upper left corner to the lower right corner that move from a cell to its neighboring cell to the right or down. Each path is associated with the string that is formed by all the letters in the cells the path visits. Thus, the length of each string is 2n−1.

Find the lexicographically smallest string that can be associated with a path after changing letters in at most k cells of the matrix.

A string a is lexicographically smaller than a string b, if the first different letter in a and b is smaller in a.

Input
The first line contains two integers n and k (1≤n≤2000, 0≤k≤n2) — the size of the matrix and the number of letters you can change.
Each of the next n lines contains a string of n lowercase English letters denoting one row of the matrix.

Output
Output the lexicographically smallest string that can be associated with some valid path after changing no more than k letters in the matrix.

解法

先考虑没有修改。
因为要答案字典序最小,所以对于每一步能取最小的字母就取最小的。
又因为只能往下或者往右走,所以在走的步数一定时,走到的位置就可知。
既然这样,我们只要保证能更新答案的状态的字母是相同步数中最小的,就能保证取到最小的字典序。
就像下面这样。

for(int step=1;step<n*2;step++){
    for(int j=max(1,step-n+1);j<=min(step,n);j++){
        int x=j,y=step-j+1;
        if(node[x-1][y].vis&&node[x-1][y].v==Min[step-1])
            node[x][y].vis=1;
        if(node[x][y-1].vis&&node[x][y-1].v==Min[step-1])
            node[x][y].vis=1;
        if(!node[x][y].vis)continue;
        Min[step]=min(Min[step],Map[x][y]);
    }
}

但是,cf加了一个修改的操作。
乍一看很难以操作,但是我们可以发现,改动的最优贡献肯定是把前缀非 “a” 的字母改为 “a”。
而此时前缀字母都相等时,最优的状态不就是有最少修改次数的情况嘛。
于是只需要对上面的代码小改一下。

for(int step=1;step<n*2;step++){
    for(int j=max(1,step-n+1);j<=min(step,n);j++){
        int x=j,y=step-j+1;
        if(node[x-1][y].vis&&node[x-1][y].v==Min[step-1]){
            if(!node[x][y].vis){
                node[x][y].vis=1;
                node[x][y].f=node[x-1][y].f;
            }else{
                node[x][y].f=min(node[x][y].f,node[x-1][y].f);
            }
        }
        if(node[x][y-1].vis&&node[x][y-1].v==Min[step-1]){
            if(!node[x][y].vis){
                node[x][y].vis=1;
                node[x][y].f=node[x][y-1].f;
            }else{
                node[x][y].f=min(node[x][y].f,node[x][y-1].f);
            }
        }
        if(!node[x][y].vis)continue;
        if(node[x][y].f!=k&&node[x][y].Map!='a')node[x][y].f++,node[x][y].v='a';
        else node[x][y].v=node[x][y].Map;
        Min[step]=min(Min[step],node[x][y].v);
    }
}

这样就可以处理修改的操作了。
完整代码

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
int n,k;
struct Node{
    int f;
    bool vis;
    char Map,v;
}node[2005][2005];
char Min[5000];
void Dp(){
    for(int step=1;step<n*2;step++){
        for(int j=max(1,step-n+1);j<=min(step,n);j++){
            int x=j,y=step-j+1;
            if(node[x-1][y].vis&&node[x-1][y].v==Min[step-1]){
                if(!node[x][y].vis){
                    node[x][y].vis=1;
                    node[x][y].f=node[x-1][y].f;
                }else{
                    node[x][y].f=min(node[x][y].f,node[x-1][y].f);
                }
            }
            if(node[x][y-1].vis&&node[x][y-1].v==Min[step-1]){
                if(!node[x][y].vis){
                    node[x][y].vis=1;
                    node[x][y].f=node[x][y-1].f;
                }else{
                    node[x][y].f=min(node[x][y].f,node[x][y-1].f);
                }
            }
            if(!node[x][y].vis)continue;
            if(node[x][y].f!=k&&node[x][y].Map!='a')node[x][y].f++,node[x][y].v='a';
            else node[x][y].v=node[x][y].Map;
            Min[step]=min(Min[step],node[x][y].v);
        }
    }
}
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        getchar();
        for(int j=1;j<=n;j++){
            scanf("%c",&node[i][j].Map);
            node[i][j].f=n*n;
        }
    }
    for(int i=1;i<n*2;i++)Min[i]='z';
    node[1][0].vis=node[0][1].vis=1;
    Dp();
    for(int i=1;i<n*2;i++)printf("%c",Min[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值