题解 [USACO 2013 Jan]Island Travels

状压dp,
大概是这题 + 这题
\(~bfs~\)求出联通块(岛屿),每个联通块就是一个独立的节点,
所以两点的距离也可以用\(~bfs~\)求?
这样其实是错的,\(~bfs~\)出来的不是最短距离,还要用上\(~Floyd~\)。
最后套\(~Hamiton~\)板子即可。

\(Code\):

#include<bits/stdc++.h>
using namespace std;
const int N=51;
const int M=5000;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int n,m,cnt,fr[N][N],d[N][N],ans=INT_MAX,f[1<<17][17];
char mp[N][N];
bool vis[N][N];
void Floyd(){
	for(int k=1;k<=cnt;k++)
		for(int i=1;i<=cnt;i++)
			for(int j=1;j<=cnt;j++)
				d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
void bfs(int x,int y){
	queue<int>q1,q2;
	q1.push(x);q2.push(y);
	vis[x][y]=true;
	fr[x][y]=cnt;
	while(!q1.empty()){
		int nx=q1.front();q1.pop();
		int ny=q2.front();q2.pop();
		for(int i=0;i<4;i++){
			int fx=nx+dx[i];
			int fy=ny+dy[i];
			if(fx<1||fy<1||fx>n||fy>m||vis[fx][fy]||mp[fx][fy]!='X')
				continue;
			fr[fx][fy]=cnt;vis[fx][fy]=true;
			q1.push(fx);q2.push(fy);
		}
	}	
}
void BFS(int x,int y){
	queue<int>q1,q2,q3;
	q1.push(x);
	q2.push(y);
	q3.push(0);
	vis[x][y]=true;
	while(!q1.empty()){
		int nx=q1.front();q1.pop();
		int ny=q2.front();q2.pop();
		int len=q3.front();q3.pop();
		for(int i=0;i<4;i++){
			int fx=nx+dx[i];
			int fy=ny+dy[i];
			if(fx<1||fy<1||fx>n||fy>m||vis[fx][fy]||mp[fx][fy]=='.')
				continue;
			d[fr[x][y]][fr[fx][fy]]=min(d[fr[x][y]][fr[fx][fy]],len);
//			cout<<fr[x][y]<<' '<<fr[fx][fy]<<' '<<len+1<<endl;
			vis[fx][fy]=true;
			q1.push(fx);q2.push(fy);q3.push(len+1);
		}
	}	
}
void DP(){
	memset(f,0x3f,sizeof(f));
	for(int i=1;i<=cnt;i++)
		f[1<<(i-1)][i]=0;
	for(int i=1;i<(1<<cnt);i++)
		for(int j=1;j<=cnt;j++)if(i>>(j-1)&1)
			for(int k=1;k<=cnt;k++)if((i^(1<<(j-1)))>>(k-1)&1)
				f[i][j]=min(f[i][j],f[i^(1<<(j-1))][k]+d[k][j]);
	for(int i=1;i<=cnt;i++)
		ans=min(ans,f[(1<<cnt)-1][i]);	
	printf("%d",ans);
}
int main(){
	memset(d,0x3f,sizeof(d));
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			cin>>mp[i][j];
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			if(vis[i][j]||mp[i][j]!='X')continue;
			cnt++;bfs(i,j);
        }
    memset(vis,0,sizeof(vis));
//    for(int i=1;i<=n;i++){
//    	for(int j=1;j<=m;j++)
//    		if(mp[i][j]!='X')cout<<mp[i][j]<<' ';
//    		else cout<<fr[i][j]<<' ';
//    	cout<<endl;
//	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			if(mp[i][j]!='X')continue;
			memset(vis,0,sizeof(vis));
			d[i][i]=0;BFS(i,j);
		}
//	for(int i=1;i<=cnt;i++){
//		for(int j=1;j<=cnt;j++)
//			printf("%d---->%d: %d\n",i,j,d[i][j]);
//	}
	Floyd();
	DP();
	return 0;
}
/*
4 5
...XX
.XXX.
X...X
.XXXX
*/
/*
2 5
. . . 1 1
. 2 2 X .
*/
上一篇:P4949 最短距离(基环树+树链剖分)


下一篇:Lecture4_1&4_2.多维随机变量及其概率分布