【题解】灰化肥,会挥发

题目链接

题目大意:给定一张图(四联通),求图上从(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....*.........
*.*.*..............*
..*...*.......*.....
...............****.
....................
........*..........*
..*...........*.....
..*........*.*......
**.*........*.......
..........*......*..
....*........*......
*.*....*........*..*
*.*...........*.*...
.*..*......*........
......*.......*.....
...*......*.........
*/
原文地址:https://www.cnblogs.com/h-lka/p/12404022.html