【题解】灰化肥,会挥发

题目链接

题目大意:给定一张图(四联通),求图上从\(A\)点走完所有\(key\)点的最短路径,输出字典序最小的路径

这里用一个小\(trick\):求出所有关键点两两之间的距离,就可以把图给扔了。

考虑到\(key\)点的数量很少,考虑一波状压。

设计状态\(dp[i][j]\)表示当前点在\(j\),状态为\(i\)的最短路径。

那么显然:

\[dp[i][j]=k:\in j_{next} \min(dp[i|(1<<k)][k],dp[i][j]+dis[j][k])\]

同时维护一个路径即可。需要注意的是,当枚举到更新状态和当前状态路径相同的时候,要注意字典序是不是可以更新。

状压储存点从\(0\)开始比较好。注意的是,点需要保证第一个点是\(A\),否则不能保证正确。

代码实现的细节比较多。位运算不要写错。

注意这题卡空间。
\(\text{Code:}\)

#include<bits/stdc++.h>
using namespace std;
int r,c,n,last,pos;
char mp[501][501];
const int dx[4]={0,1,0,-1};
const int dy[4]={1,0,-1,0};
struct edge{int x,y;}p[16];
int dp[1<<16][16],tot;
int dis[16][16],u[501][501];
string f[1<<16][16],res;
void BFS(edge s){
    queue<edge>q;
    memset(u,0,sizeof(u));
    q.push(s);u[s.x][s.y]=1;
    while(!q.empty()){
        edge tmp=q.front();q.pop();
        for(int i=0;i<4;++i){
            int x=tmp.x+dx[i],y=tmp.y+dy[i];
            if(x<1||x>r||y<1||y>c||u[x][y]||mp[x][y]=='*')continue;
            u[x][y]=u[tmp.x][tmp.y]+1;q.push((edge){x,y});
        }
    }
}
bool cmp(edge a,edge b){
    return mp[a.x][a.y]<mp[b.x][b.y];
}
int main(){
    scanf("%d%d%d",&r,&c,&n);
    for(int i=1;i<=r;++i)
        scanf("%s",mp[i]+1);
    for(int i=1;i<=r;++i)
        for(int j=1;j<=c;++j)
            if(mp[i][j]>='A'&&mp[i][j]<='Z')p[tot++]=(edge){i,j};
    sort(p,p+tot,cmp);
    for(int i=0;i<tot;++i){
        BFS(p[i]);
        for(int j=0;j<tot;++j)dis[i][j]=u[p[j].x][p[j].y]-1;
    }
    
    //for(int i=0;i<tot;++i)
    //  for(int j=0;j<tot;++j)
    //      cout<<mp[p[i].x][p[i].y]<<"->"<<mp[p[j].x][p[j].y]<<":"<<dis[i][j]<<endl;
    
    memset(dp,63,sizeof(dp));
    dp[1][0]=0;f[1][0]="A";
    for(int i=1;i<(1<<tot);++i){
        if(!(i&1))continue;
        for(int j=0;j<tot;++j){
            if(!(i&(1<<j)))continue;//start->j
            for(int k=1;k<tot;++k){
                if(i&(1<<k))continue;//goal->k
                if(dp[i|(1<<k)][k] > dp[i][j] + dis[j][k]){
                    dp[i|(1<<k)][k] =dp[i][j] + dis[j][k];
                    f[i|(1<<k)][k] =f[i][j] + mp[p[k].x][p[k].y];
                }
                else if(dp[i|(1<<k)][k] == dp[i][j] + dis[j][k])
                    if(f[i|(1<<k)][k] > f[i][j] + mp[p[k].x][p[k].y])
                        f[i|(1<<k)][k] = f[i][j] + mp[p[k].x][p[k].y];
            }
        }
    }
    last=(1<<tot)-1;
    pos=dp[last][1];
    res=f[last][1];
    for(int i=2;i<tot;++i){
        if(dp[last][i]<pos){
            pos=dp[last][i];
            res=f[last][i];
        }
        else if(dp[last][i]==pos&&res>f[last][i])res=f[last][i];
    }
    printf("%d\n",pos);
    cout<<res<<endl;
    return 0;
}
/*
20 20 5
E......*...........*
B.....*.............
A................*..
..C............*....
..*..D....*.........
*.*.*..............*
..*...*.......*.....
...............****.
....................
........*..........*
..*...........*.....
..*........*.*......
**.*........*.......
..........*......*..
....*........*......
*.*....*........*..*
*.*...........*.*...
.*..*......*........
......*.......*.....
...*......*.........
*/

猜你喜欢

转载自www.cnblogs.com/h-lka/p/12404022.html