刚开始打算用DFS做,但是没想到特别好的剪枝方法,后来想到将图的进行编号然后重新构图,再加上一个编号为0的起点以及加一个汇点,然后用spfa求最短路径即可。
需要注意的是加起点的时候需要把第一行所有的编号进行连边,对应的也需要对最后一行与汇点进行连边。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int maxn=1e4+100;
const int inf=1<<29;
char str[25][25];
int n,m,e,ans,cur,num[25][25],pnt[maxn],nxt[maxn],head[maxn],dist[maxn];
int movex[4]={1,-1,0,0},movey[4]={0,0,-1,1};
bool vis[25][25],visit[505];
bool isborder(int x,int y)
{
if(x<=0||x>n||y<=0||y>m)
return true;
return false;
}
void DFS(int x,int y)
{
for(int i=0;i<4;i++)
{
int itx=x+movex[i];
int ity=y+movey[i];
if(isborder(itx,ity)||num[itx][ity])
continue;
if(str[itx][ity]==str[x][y])
{
num[itx][ity]=cur;
DFS(itx,ity);
}
}
}
void addedge(int u,int v)
{
pnt[e]=v;nxt[e]=head[u];head[u]=e++;
}
void GetWay(int x,int y)
{
for(int i=0;i<4;i++)
{
int itx=x+movex[i];
int ity=y+movey[i];
if(isborder(itx,ity)||vis[itx][ity])
continue;
vis[itx][ity]=1;
if(num[itx][ity]==num[x][y])
GetWay(itx,ity);
else
addedge(num[x][y],num[itx][ity]);
}
}
void Spfa()
{
for(int i=0;i<=cur;i++)
dist[i]=inf;
dist[0]=0;
queue<int> q;
q.push(0);
memset(visit,0,sizeof(visit));
while(!q.empty())
{
int u=q.front();
q.pop();
visit[u]=0;
for(int i=head[u];i!=-1;i=nxt[i])
{
int v=pnt[i];
if(dist[v]>dist[u]+1)
{
dist[v]=dist[u]+1;
if(!visit[v])
{
q.push(v);
visit[v]=1;
}
}
}
}
printf("%d\n",dist[cur]-1);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
ans=e=0;
cur=1;
memset(head,-1,sizeof(head));
memset(num,0,sizeof(num));
for(int i=1;i<=n;i++)
scanf("%s",str[i]+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(num[i][j])
continue;
num[i][j]=cur;
DFS(i,j);
cur++;
}
memset(visit,0,sizeof(visit));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
memset(vis,0,sizeof(vis));
if(visit[num[i][j]])
continue;
visit[num[i][j]]=1;
GetWay(i,j);
}
int last=0;
for(int i=1;i<=m;i++)
{
if(num[1][i]!=last)
{
addedge(0,num[1][i]);
last=num[1][i];
}
}
last=0;
for(int i=1;i<=m;i++)
{
if(num[n][i]!=last)
{
addedge(num[n][i],cur);
last=num[n][i];
}
}
Spfa();
}
return 0;
}