codefoces 1072 D. Minimum path(dp+bfs)

本文介绍了一种解决矩阵中从左上角到右下角字典序最小路径的问题算法,通过动态规划预处理和优先队列BFS,实现字母变化限制下的最优路径寻找。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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×nn×n filled with lowercase English letters. You can change no more than kk 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−12n−1.

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

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

Input
The first line contains two integers nn and kk (1≤n≤20001≤n≤2000, 0≤k≤n20≤k≤n2) — the size of the matrix and the number of letters you can change.

Each of the next nn lines contains a string of nn 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 kk letters in the matrix.

Examples
inputCopy
4 2
abcd
bcde
bcad
bcde
outputCopy
aaabcde
inputCopy
5 3
bwwwz
hrhdh
sepsp
sqfaf
ajbvw
outputCopy
aaaepfafw
inputCopy
7 6
ypnxnnp
pnxonpm
nxanpou
xnnpmud
nhtdudu
npmuduh
pmutsnz
outputCopy
aaaaaaadudsnz
Note
In the first sample test case it is possible to change letters ‘b’ in cells (2,1)(2,1) and (3,1)(3,1) to ‘a’, then the minimum path contains cells (1,1),(2,1),(3,1),(4,1),(4,2),(4,3),(4,4)(1,1),(2,1),(3,1),(4,1),(4,2),(4,3),(4,4). The first coordinate corresponds to the row and the second coordinate corresponds to the column.

题意:给你一张图,给你一个k值可以将任何k个字母改变,求左上到右下字典序最小的答案

思路:首先用dp[i][j]记录下走到该点全部为a的最小变化值,然后将能变成a的全部变为a
然后就用滚动的优先队列bfs 开优先队列的目的是方便直接找出所有的最小字母加入队列,然后再将每一步能向下向右走的字母加入优先队列直到走到右下角,这里要记录一下加入过队列的字母下标,不然会严重超时!!!

#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string.h>
#include<queue>
#define fi first
#define se second
#define FOR(a) for(int i=0;i<a;i++)
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" !!! "<<b<<endl;
#define show3(a,b,c) cout<<a<<" !!! "<<b<<" !!! "<<c<<endl;
#define show4(a,b,c,d) cout<<a<<" !!! "<<b<<" !!! "<<c<<" !!! "<<d<<endl;
using namespace std;

typedef long long ll;
typedef pair<int, int> P;
typedef pair<P, int> LP;
const ll inf = 0x3f3f3f3f;
const int N = 2005;
const ll mod = 998244353;

int n, m, t, x, y, k, sum, cnt, aans;
int r, c, a[N], dex[N], b[N],num[N];
char ans[5000];
int dp[N][N];
int vis[N][N], er[N];
char v[N][N];

struct node
{
	char s;
	int x,y;
	bool operator < (const node& t) const{
		return s>t.s;
	}
};
priority_queue<node> q;
priority_queue<node> tq;

bool ok(int x,int y)
{
	if(x>=0&&y<n&&y>=0&&x<n) return 1;
	return 0;
}

int main()
{
	scanf("%d%d",&n,&k);
	for(int i=0;i<n;i++) scanf("%s",v[i]);
	if(k>=2*n-1)
	{
		for(int i=1;i<2*n;i++)
		{
			printf("a");
		}
		return 0;
	}
	for(int i=0;i<=n;i++)
		for(int j=0;j<=n;j++)
			dp[i][j]=inf;
	dp[0][0]=(v[0][0]!='a');
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			if(dp[i][j]<=k) v[i][j]='a';
			dp[i+1][j]=min(dp[i+1][j],dp[i][j]+(v[i+1][j]!='a'));
			dp[i][j+1]=min(dp[i][j+1],dp[i][j]+(v[i][j+1]!='a'));
		}
	}
	//for(int i=0;i<=n;i++) cout<<v[i]<<endl;


	q.push(node{v[0][0],0,0});
	while(q.size())
	{
		char mi;
		int flag=0;

		while(q.size())
		{

			node now=q.top();
			q.pop();
			if(!flag) mi=now.s,flag=1;
			if(now.s==mi)
			{
				tq.push(now);
				//show3(now.s,now.x,now.y)
			}


		}
		//cout<<mi<<endl;
		//cout<<tq.size()<<endl;

		ans[++cnt]=mi;
		while(tq.size())
		{
			node now=tq.top();
			tq.pop();
			int x=now.x;
			int y=now.y;
			if(ok(x+1,y)&&!vis[x+1][y])
			{
				vis[x+1][y]=1;
				q.push(node{v[x+1][y],x+1,y});
				//show3(now.s,now.x,now.y)

			}
			if(ok(x,y+1)&&!vis[x][y+1])
			{
				vis[x][y+1]=1;
				q.push(node{v[x][y+1],x,y+1});
				//show3(now.s,now.x,now.y)
			}
		}

	}
	for(int i=1;i<=cnt;i++) printf("%c",ans[i]);


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值