[伪USACO]奶牛美容

传送门
这道题其实思想不是很难
就是给你一个有三个连通块的矩阵,让你染最少的点让着三个连通块连起来
看到题意,加上 n , m 50 n,m\leq50
大声喊出:

爆搜!

有几个数组
c o l [ i ] [ j ] col[i][j] 表示 ( i , j ) (i,j) 属于哪个连通块
d i s [ i ] [ j ] [ k ] dis[i][j][k] 表示 ( i , j ) (i,j) 到第 k k 个连通块的最短距离
d [ i ] [ j ] d[i][j] 表示第 i i 个连通块到第 j j 个连通块的距离

首先我们先 dfs \operatorname{dfs} 将三个连通块染色,复杂度 O ( n m ) \operatorname{O}(nm)
然后我们 bfs \operatorname{bfs} 预处理每一个点到不同连通块的最短距离,扫描起点 O ( n m ) \operatorname{O}(nm) ,每个点扫一遍加起来 O ( n 2 m 2 ) \operatorname{O}(n^2m^2)
然后我们求出每个连通块的最短距离
d [ i ] [ j ] = min { d i s [ x ] [ y ] [ i ] + d i s [ x ] [ y ] [ j ] } d[i][j]=\min \{dis[x][y][i]+dis[x][y][j]\}
那么答案就是
a n s = min { d [ 1 ] [ 2 ] + d [ 1 ] [ 3 ] , d [ 1 ] [ 3 ] + d [ 2 ] [ 3 ] , d [ 1 ] [ 3 ] + d [ 2 ] [ 3 ] } ans=\min\{d[1][2]+d[1][3],d[1][3]+d[2][3],d[1][3]+d[2][3]\}
收工
但是这样写交上去只有66分
为什么呢?
我们考虑着三个连通块最后连到一起的路径,可能是这样的

1-------3
|
|
2

也就是我们之前算的那种情况
但也有可能是这样的

1
|
K--------3
|
2

就是三个连通块连向同一个点
这个时候我们再按上面那种做法就会算重复了

所以再对这种情况取一个 min \min 就可以了
记得答案-2,因为有两个点(1个)算重复了,有四个点(3个)没有算(括号里是第二种情况)

# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;
const int N=55;
const int mod=1e9+7;
const double eps=1e-7;
template <typename T> void read(T &x){
	x=0;int f=1;
	char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
	x*=f;
}

//# pragma GCC optimize(2)
int n,m,cnt;
char s[N][N];
int a[N][N];
int dis[N][N][4];
int col[N][N];
int d[4][4];
int ans;
bool vis[N][N];
int mvx[4]={0,1,0,-1},mvy[4]={1,0,-1,0};

struct node{
	int x,y,len;	
};

void dfs(int x,int y,int color){
	col[x][y]=color;
	Rep(i,0,3){
		int x_new=x+mvx[i],y_new=y+mvy[i];
		if(x_new<1||x_new>n||y_new<1||y_new>m)continue;
		if(col[x_new][y_new])continue;
		if(!a[x_new][y_new])continue;
		dfs(x_new,y_new,color);
	}
}

void bfs(int x,int y){
	queue<node> q;
	q.push((node){x,y,0});
	memset(vis,0,sizeof(vis));
	vis[x][y]=true;
	while(!q.empty()){
		node u=q.front();q.pop();
		if(col[u.x][u.y])dis[x][y][col[u.x][u.y]]=min(dis[x][y][col[u.x][u.y]],u.len);
		Rep(i,0,3){
			int x_new=u.x+mvx[i],y_new=u.y+mvy[i];
			if(x_new<1||x_new>n||y_new<1||y_new>m)continue;
			if(vis[x_new][y_new])continue;
			vis[x_new][y_new]=true;
			q.push((node){x_new,y_new,u.len+1});
		}
	}
}

int main()
{
	memset(d,0x3f,sizeof(d));
	memset(dis,0x3f,sizeof(dis));
	read(n),read(m);
	Rep(i,1,n)scanf("%s",s[i]+1);
	Rep(i,1,n)
		Rep(j,1,m)
			if(s[i][j]=='X')
				a[i][j]=1;
	Rep(i,1,n)	
		Rep(j,1,m)
			if(a[i][j]&&!col[i][j])
				dfs(i,j,++cnt);
	Rep(i,1,n)
		Rep(j,1,m)
			bfs(i,j);
	Rep(i,1,n)
		Rep(j,1,m)
			Rep(k,1,3)
				Rep(l,1,3)
					if(k!=l)d[k][l]=min(d[k][l],dis[i][j][k]+dis[i][j][l]);
	ans=min(d[1][2]+d[1][3],min(d[1][2]+d[2][3],d[1][3]+d[2][3]));
	Rep(i,1,n)
		Rep(j,1,m)
			ans=min(ans,dis[i][j][1]+dis[i][j][2]+dis[i][j][3]);
	ans-=2;
	printf("%d\n",ans);
	return 0; 
}
发布了45 篇原创文章 · 获赞 52 · 访问量 9637

猜你喜欢

转载自blog.csdn.net/devout_/article/details/104311967