题目大意:给定一张图(四联通),求图上从(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),否则不能保证正确。
代码实现的细节比较多。位运算不要写错。
注意这题卡空间。
( ext{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
",pos);
cout<<res<<endl;
return 0;
}
/*
20 20 5
E......*...........*
B.....*.............
A................*..
..C............*....
..*..D....*.........
*.*.*..............*
..*...*.......*.....
...............****.
....................
........*..........*
..*...........*.....
..*........*.*......
**.*........*.......
..........*......*..
....*........*......
*.*....*........*..*
*.*...........*.*...
.*..*......*........
......*.......*.....
...*......*.........
*/