P2124 奶牛美容

题目描述

输入输出格式

输入格式:

输出格式:

输入输出样例

输入样例#1: 
6 16
................
..XXXX....XXX...
...XXXX....XX...
.XXXX......XXX..
........XXXXX...
..XXX....XXX....
输出样例#1: 
4

Solution:

  本题一眼想到搜索(考试时打了半天,没调对~~手动滑稽~~)。事后讨论,发现神佬的思路有可行性也有一些错误,于是从中启发,再结合题解,便改出了类$floyd$的算法。

  首先,用一次$dfs$处理出$3$个连通块并标记,实现比较简单。

  再就是骚操作了,处理出每个$s[i][j]==X$的点所在连通块到其它所有点的最小曼哈顿距离$dis[k][i][j]$(表示第$k$个连通块到$[i,j]$点的最小曼哈顿距离)。

  然后对于每个是连通块上的点(即$s[i][j]==X$的点),去更新这个点所在连通块与其它连通块的最短距离($f[i][j]$表示第$i$个连通块与第$j$个连通块的最短距离),很显然的状态转移方程为:$f[p][q]=min(f[p][q],dis[q][i][j]),\;s[i][j]\in p$,(记得$f[p][q]=f[q][p]$)。

  然后就处理出了$3$个连通块两两之间的最短距离,则$ans$初值是$3$条边中$2$条搭配的最小值(因为要使$3$个连通块连通只要连$2$条边),至于为什么是初值赋值为这个最小值呢?

  那是因为可能存在两两连通块之间共用了点的情况,举个例子:

  $\begin{Bmatrix}
 X\;.\;.\;.\;X\\
 .\;\;.\;.\;.\;\;.\\
 .\;\;.\;.\;.\;\;. \\
 .\;.\;X\;.\;.
\end{Bmatrix}$

  此时求出的$3$个连通块之间的最小距离和为$9$则需要加的$X$个数为$9-2=7$(减$2$是很显然的道理,因为我们是以坐标算曼哈顿距离,两个点之间曼哈顿路径上的点数应该等于曼哈顿距离减$1$(有点类似于小学奥数的植树间隔问题),那么三个点之间实际上就是两个两个点之间的点数,显然是减$2$(怎么感觉自己说的有点绕,~手动滑稽,不信自己模拟~)),但这个例子的答案显然因该是$5$。

  很容易发现,上述情况属于三个连通块之间由非连通块上的点搭桥相连的情况(这不还是$floyd$嘛)。于是我们处理出初值$ans$后,还应该枚举中间点,计算三个点之间共用点搭桥的情况的最小值,更新$ans$。

  那么最后答案就是$ans-2$了。时间复杂度$O(n^3)$(这也只是最坏复杂度,基本体现在预处理枚举每个连通块到其它所有点的距离上了),但还是很轻易本题就$AC$了(貌似最优解!)。

  本题给我的启发就是:

  1、其实可以将连通块个数再增多,那么就是跑最小生成树处理初值$ans$,同理继续枚举中间点连接各连通块。

  2、其实$50*50$的数据用此方法还是很水的,可以增大数据至少到$200*200$。

代码:

 1 // luogu-judger-enable-o2
 2 #include<bits/stdc++.h>
 3 #define il inline
 4 #define ll long long
 5 #define debug printf("%d %s\n",__LINE__,__FUNCTION__)
 6 using namespace std;
 7 int n,m,ans=520520520,p[55][55],cnt,f[55][55],tot,dis[4][55][55];
 8 int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
 9 char s[55][55];
10 bool vis[55][55],lian[4];
11 il void change(int x,int y,int c){
12     if(vis[x][y])return ;
13     if(s[x][y]=='X'){vis[x][y]=1;p[x][y]=c;}
14     else return;
15     for(int i=0;i<4;i++){
16         int xx=dx[i]+x,yy=dy[i]+y;
17         change(xx,yy,c);
18     }
19 }
20 il void dfs(int kuai,int x,int y){
21     for(int i=1;i<=n;i++)
22         for(int j=1;j<=m;j++)
23             dis[kuai][i][j]=min(dis[kuai][i][j],abs(i-x)+abs(j-y));
24 }
25 int main()
26 {
27     cin>>n>>m;
28     for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
29     for(int i=1;i<=n;i++)
30         for(int j=1;j<=m;j++)
31         if(s[i][j]=='X'&&!vis[i][j])change(i,j,++cnt);
32     memset(dis,0x3f,sizeof(dis));
33     for(int i=1;i<=n;i++)
34         for(int j=1;j<=m;j++)
35         if(s[i][j]=='X')dfs(p[i][j],i,j);
36     memset(f,0x3f,sizeof(f));
37     for(int i=1;i<=n;i++)
38         for(int j=1;j<=m;j++)
39         if(s[i][j]=='X'){
40             f[p[i][j]][1]=min(f[p[i][j]][1],dis[1][i][j]);
41             f[p[i][j]][2]=min(f[p[i][j]][2],dis[2][i][j]);
42             f[p[i][j]][3]=min(f[p[i][j]][3],dis[3][i][j]);
43             f[1][p[i][j]]=f[p[i][j]][1];
44             f[2][p[i][j]]=f[p[i][j]][2];
45             f[3][p[i][j]]=f[p[i][j]][3];
46     }
47     ans=min(f[1][2]+f[2][3],min(f[1][3]+f[1][2],f[1][3]+f[2][3]));
48     for(int i=1;i<=n;i++)
49         for(int j=1;j<=m;j++)
50             ans=min(ans,dis[1][i][j]+dis[2][i][j]+dis[3][i][j]);
51     cout<<ans-2;
52     return 0;
53 }

 

猜你喜欢

转载自www.cnblogs.com/five20/p/8903484.html
今日推荐