zoukankan      html  css  js  c++  java
  • CF1031D Solution

    题目链接

    题解

    易得为使序列最小,前(k)个经过的点一定都是(a),而这些经过的点中一些原本即为(a)不用变换,因此用(f)数组记录到点((i,j))能经过(a)的最大数量。另设(maxs)表示只经过原本为(a)或变换后为(a)的点的最大步数,如果(f_{i,j}+k)(最大(a)数量)(=i+j-1)(到((i,j))路径)(=maxs),说明((i,j))处于可以为(a)的点中的“边缘”,再往后走就需要bfs了。

    BFS:为了字典序最小,每一步到达的节点都是这一步可到达的节点中值最小的,因此需要(pos)记录当前节点为第(pos)步到达的。此外,还需要用(mx)记录本步可到达最小的值,而用(mn)记录下一步可到达的最小值,以此维护(mx)。这样第一次遍历到一个节点的路径一定是最优的,所以用(vis)数组保证每个节点只被搜索一遍。至于记录路径,用(pre)表示上一个转移来的节点在队列中的编号即可,此方法只可以在手动队列中使用。

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2010;
    struct node {int pos,pre,x,y;} q[N*N];
    int f[N][N],cnt,hd=1,tl;
    int dx[3]={0,1},dy[3]={1,0};
    char mp[N][N],ans[N];
    bool vis[N][N];
    void print()
    {
    	while(tl!=-1)
    	{
    		ans[++cnt]=mp[q[tl].x][q[tl].y];
    		tl=q[tl].pre;
    	}
    	for(int i=cnt;i>=1;i--) cout<<ans[i];
    }//输出路径
    int main()
    {
    	ios::sync_with_stdio(0);
    	int n,k;	
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
        //处理f数组
    	f[1][1]=(mp[1][1]=='a');
    	for(int i=2;i<=n;i++) f[i][1]=f[i-1][1]+(mp[i][1]=='a'),f[1][i]=f[1][i-1]+(mp[1][i]=='a');
    	for(int i=2;i<=n;i++)
    		for(int j=2;j<=n;j++) f[i][j]=max(f[i][j-1],f[i-1][j])+(mp[i][j]=='a');
        //计算maxs
    	int maxs=0;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			if(f[i][j]+k>=i+j-1) maxs=max(maxs,i+j-1);
    	for(int i=1;i<=maxs;i++) cout<<'a';
        //特判
    	if(maxs==2*n-1) return 0;
    	if(n==1) {cout<<mp[1][1]; return 0;}
        //寻找"边缘"节点,使它们可以到达的节点入队
    	int mn='z'+1,mx;
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=n;j++)
    		{
    			if(j+i-1!=maxs || f[i][j]+k!=maxs) continue;
    			for(int d=0;d<2;d++)
    			{
    				int tx=i+dx[d],ty=j+dy[d];	
    				if(tx>n || ty>n || mp[tx][ty]>mn || vis[tx][ty]) continue;
    				mn=mp[tx][ty]; vis[tx][ty]=1;
    				q[++tl]=(node){1,-1,tx,ty};
    				if(tx==n && ty==n) {print(); return 0;}
    			}
    		}
    	}
    	if(!maxs) q[++tl]=(node){1,-1,1,1};
        //BFS
    	while(hd<=tl)
    	{
    		int ps=q[hd].pos,x=q[hd].x,y=q[hd].y;
    		if(ps==q[hd-1].pos+1) {mx=mn; mn='z'+1;}
    		if(mp[x][y]>mx) {hd++; continue;}
    		for(int i=0;i<2;i++)
    		{
    			int tx=x+dx[i],ty=y+dy[i];
    			if(tx>n || ty>n || mp[tx][ty]>mn || vis[tx][ty]) continue;
    			mn=mp[tx][ty]; vis[tx][ty]=1;
    			q[++tl]=(node){ps+1,hd,tx,ty};
    			if(tx==n && ty==n) {print(); return 0;}
    		}
    		hd++;
    	}
    	return 0;
    }
    

    参考博客

  • 相关阅读:
    如何经营爱情!
    document.getElementById('myframe')和window.frames[i]的区别
    [WPF] 使用 MVVM Toolkit 构建 MVVM 程序
    [WPF] 使用 Visual Studio App Center 持续监视应用使用情况和问题
    centos 7执行yum update时在clean up阶段挂住
    实现线性结构转树形结构(生成无限层级菜单)
    中文分词——HMM算法
    中文分词——最大匹配法
    爱因斯坦求和约定
    jupyter notebook美化
  • 原文地址:https://www.cnblogs.com/violetholmes/p/14257493.html
Copyright © 2011-2022 走看看