分析:求出每个集合点到其他所有点的最短距离,然后枚举每个金子,看他是否在两点之间的最短路上,如果在的话,以路径编号和金子在矩阵里的编号(i*m+j)建边。
代码:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <queue>
using namespace std;
const int maxn=10005;
const int maxm=1000005;
const int INF=1000000000;
struct EdgeNode
{
int to;
int next;
}edge[maxm];
int head[maxn],cnt;
void add(int x,int y)
{
edge[cnt].to=y;
edge[cnt].next=head[x];
head[x]=cnt++;
}
char g[105][105];
int zs,js,n,m,pre[maxn];
bool v[maxn],vis[105][105];
int bj[maxn],dis[105][maxn];
int zm[maxn],hj[maxn];
int d[5][3]={{-1,0},{1,0},{0,-1},{0,1}};
struct p
{
int x,y,ct;
friend bool operator < (p a,p b)
{
return a.ct>b.ct;
}
};
void init()
{
cnt=0;
memset(head,-1,sizeof(head));
memset(bj,-1,sizeof(bj));
for(int i=0;i<=55;i++)
for(int j=0;j<=n*m;j++)
dis[i][j]=INF;
}
int zh(char s)
{
if(s>='A'&&s<='Z')return s-'A'+1;
if(s>='a'&&s<='z')return s-'a'+1+26;
}
int yj(int x,int y)
{
if(x<0||x>=n||y<0||y>=m)return 1;
return 0;
}
void bfs(int w)
{
int st=zm[w],t;
p first,next;
priority_queue<p>Q;
memset(vis,0,sizeof(vis));
first.ct=0; first.x=st/m; first.y=st%m;
Q.push(first);
vis[first.x][first.y]=1;
while(!Q.empty())
{
first=Q.top();
Q.pop();
for(int i=0;i<4;i++){
next.x=first.x+d[i][0];
next.y=first.y+d[i][1];
next.ct=first.ct+1;
if(!vis[next.x][next.y]&&!yj(next.x,next.y)&&g[next.x][next.y]!='#')
{
vis[next.x][next.y]=1;
Q.push(next);
t=next.x*m+next.y;
dis[w][t]=next.ct;
}
}
}
}
int dfs(int x)
{
int y;
for(int i=head[x];i!=-1;i=edge[i].next)
{
y=edge[i].to;
if(!v[y]){
v[y]=1;
if(!pre[y]||dfs(pre[y]))
{
pre[y]=x;
return true;
}
}
}
return false;
}
int erfenpipei()
{
int sum=0;
memset(pre,0,sizeof(pre));
for(int i=1;i<=n;i++)
{
memset(v,0,sizeof(v));
if(dfs(i))sum++;
}
return sum;
}
int main()
{
int i,j,t;
while(~scanf("%d%d",&n,&m))
{
zs=js=0;
init();
for(i=0;i<n;i++){
scanf("%s",g[i]);
for(j=0;j<m;j++){
if(g[i][j]=='#')continue;
if(g[i][j]=='.')continue;
if(g[i][j]=='*'){
hj[++js]=i*m+j;
}
else{
t=zh(g[i][j]);
bj[t]=++zs;
zm[t]=i*m+j;
}
}
}
for(i=1;i<=zs;i++)bfs(i);
for(i=1;i<zs;i++)
{
if(bj[i]==-1||bj[i+1]==-1)break;
if(dis[i][zm[i+1]]==INF)break;
}
if(i<zs){printf("-1\n");continue;}
else{
for(i=1;i<zs;i++){
for(j=1;j<=js;j++){
if(dis[i][hj[j]]+dis[i+1][hj[j]]==dis[i][zm[i+1]])
add(i,hj[j]);
}
}
n=zs;
printf("%d\n",erfenpipei());
}
}
return 0;
}