现在我们有三个国家,每个国家都是一个联通块,用数字1、2和3来表示。
现在我们希望在点的位子上建立路,使得三个国家连通起来,现在问需要建立路的最小个数。
思路:
因为只有三个国家,所以我们用每个国家求一次单源最短路,记录dist【i】【x】【y】表示i号国家想要和点(x,y)进行连通的话,需要建立的路的个数。
那么对应,我们只要O(nm)的去枚举一个交汇点,那么dist【1】【x】【y】+dist【2】【x】【y】+dist【3】【x】【y】就是答案,如果点(x,y)是点的话,那么对应还要减去2.
我们去Bfs的时候,注意到达每个点的时候,需要求最短路,所以我们这里直接用队列Bfs的话可能会TLE,用优先队列优化一下就不会了TAT、
Ac代码:
#include<stdio.h>
#include<queue>
#include<string.h>
#include<algorithm>
#include<stack>
using namespace std;
struct node
{
int x,y,step;
bool friend operator <(node a ,node b)
{
return a.step>b.step;
}
}now,nex;
char a[1050][1050];
int dodo[400];
int dist[5][1050][1050];
int vis[1050][1050];
int fx[4]={0,0,1,-1};
int fy[4]={1,-1,0,0};
int n,m;
void Bfs(int x,int y,int dd)
{
memset(vis,0,sizeof(vis));
priority_queue<node>s;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
dist[dd][i][j]=0x3f3f3f3f;
if(a[i][j]-'0'==dd)
{
now.x=i;
now.y=j;
now.step=0;
s.push(now);
dist[dd][i][j]=0;
}
}
}
while(!s.empty())
{
now=s.top();
vis[now.x][now.y]=0;
s.pop();
for(int i=0;i<4;i++)
{
nex.x=now.x+fx[i];
nex.y=now.y+fy[i];
nex.step=now.step;
if(nex.x>=0&&nex.x<n&&nex.y>=0&&nex.y<m&&a[nex.x][nex.y]!='#')
{
if(a[nex.x][nex.y]=='.')
{
nex.step++;
}
if(dist[dd][nex.x][nex.y]>nex.step)
{
dist[dd][nex.x][nex.y]=nex.step;
if(vis[nex.x][nex.y]==0)
{
s.push(nex);
}
}
}
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(dodo,0,sizeof(dodo));
for(int i=0;i<n;i++)scanf("%s",a[i]);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(dodo[a[i][j]]==0&&a[i][j]>='1'&&a[i][j]<='3')
{
Bfs(i,j,a[i][j]-'0');dodo[a[i][j]]=1;
}
}
}
int output=0x3f3f3f3f;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(a[i][j]!='#')
{
int flag=0;
int ans=0;
for(int dd=1;dd<=3;dd++)
{
if(dist[dd][i][j]==0x3f3f3f3f)flag=1;
ans+=dist[dd][i][j];
}
if(flag==1)continue;
if(a[i][j]=='.')ans-=2;
output=min(output,ans);
}
}
}
if(output==0x3f3f3f3f)printf("-1\n");
else
printf("%d\n",output);
}
}