Codeforces 83C

本文介绍了一种寻找图中从起点到终点字典序最小的最短路径算法。该算法首先通过广度优先搜索找到最短路径,再在这些路径中找到字典序最小的一条。适用于边权均为1的情况。

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

求字典序最小的最短路
先求最短路,因为边权都为1,所以直接沿着最短路边广搜出一条
字典序最小的就好了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
typedef __int64 LL;
const int N=51;

char tt[10];
char mp[N*N];
char ans[N*N],ans1[N*N];
int c1,c2,c3,c4;
int s,t,clock;
int vis[N][N],dis[N][N],wis[N][N],pre[N][N];
queue<int> qq;
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int n,m,k;
char ss[N][N];

////c1 dangqian c2 zong
void fun(){
    //for(int i=0;i<c1;i++)printf("%c ",tt[i]);printf("\n");
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            wis[i][j]=0;
            for(int k1=0;k1<c1;k1++)if(ss[i][j]==tt[k1])wis[i][j]=1;
            if(ss[i][j]=='S'||ss[i][j]=='T')wis[i][j]=1;
        }
    }

    clock++;
    qq.push(t);dis[t/m][t%m]=0;vis[t/m][t%m]=clock;
    while(!qq.empty()){
        int u=qq.front();qq.pop();
        int x=u/m,y=u%m;
        for(int i=0;i<4;i++){
            int xx=x+dir[i][0],yy=y+dir[i][1];
            if(xx>=0&&xx<n&&yy>=0&&yy<m&&wis[xx][yy]){
                if(vis[xx][yy]!=clock){
                    vis[xx][yy]=clock;dis[xx][yy]=dis[x][y]+1;qq.push(xx*m+yy);
                }
            }
        }
    }
    if(vis[s/m][s%m]!=clock||dis[s/m][s%m]-1>c3)return ;
    //printf("%d\n",dis[s/m][s%m]);
    char ch[2]={'S','a'+30};

    int dep=dis[s/m][s%m];
    clock++;
    qq.push(s);vis[s/m][s%m]=clock;pre[s/m][s%m]=-1;
    while(!qq.empty()){
        int u=qq.front();qq.pop();
        int x=u/m,y=u%m;
        if(dis[x][y]<dep){
            dep=dis[x][y],ch[0]=ch[1];ch[1]='a'+30;
        }
        //printf("%d %d %c\n",x,y,ch[0]);
        if(ss[x][y]>ch[0])continue;
        for(int i=0;i<4;i++){
            int xx=x+dir[i][0],yy=y+dir[i][1];
            if(xx>=0&&xx<n&&yy>=0&&yy<m&&wis[xx][yy]&&dis[xx][yy]==dep-1){
                if(vis[xx][yy]!=clock){
                    vis[xx][yy]=clock;pre[xx][yy]=u;qq.push(xx*m+yy);
                    ch[1]=min(ch[1],ss[xx][yy]);
                }
            }
        }
    }

    c4=dis[s/m][s%m]-1;
    int u=t;
    for(int i=0;i<c4;i++){
        u=pre[u/m][u%m];
        int x=u/m,y=u%m;
        ans1[c4-i-1]=ss[x][y];
    }
    if(c4==c3){
        for(int i=0;i<c3;i++){
            if(ans[i]>ans1[i])break;
            else if(ans[i]<ans1[i])return ;
        }
    }
    for(int i=0;i<c4;i++)ans[i]=ans1[i];c3=c4;
    //for(int i=0;i<c3;i++)printf("%c",ans[i]);printf("\n");
}
int main(){
    #ifdef DouBi
    freopen("in.cpp","r",stdin);
    #endif // DouBi
    while(scanf("%d%d%d",&n,&m,&k)!=EOF){
        c2=0;for(int i=0;i<n;i++){
            scanf("%s",ss[i]);
            for(int j=0;j<m;j++){
                if(ss[i][j]=='S')s=i*m+j;
                else if(ss[i][j]=='T')t=i*m+j;
                else mp[c2++]=ss[i][j];
            }
        }
        sort(mp,mp+c2);c2=unique(mp,mp+c2)-mp;
        c3=N*N+10;memset(vis,0,sizeof(vis));clock=0;
        fun();
        for(int i=0;i<c2;i++){
            tt[0]=mp[i],c1=1;fun();
            if(c1==k)continue;
            for(int j=i+1;j<c2;j++){
                tt[1]=mp[j],c1=2;fun();
                if(c1==k)continue;
                for(int k1=j+1;k1<c2;k1++){
                    tt[2]=mp[k1],c1=3;fun();
                    if(c1==k)continue;
                    for(int l=k1+1;l<c2;l++){
                        tt[3]=mp[l],c1=4;fun();
                    }
                }
            }
        }
        //printf("%d\n",c3);
        if(c3==N*N+10)printf("-1\n");
        else {
            for(int i=0;i<c3;i++)printf("%c",ans[i]);printf("\n");
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值