Time Limit: 1000MS | Memory Limit: 65536K | |||
Description
你喜欢寻宝游戏吗?今天,小明就要和他的朋友展开一场冒险之旅。他们可能在路上找到许多黄金。
小明的朋友非常聪明,已经绘制出了一张寻宝地图,为了简单化,地图上只有三种标识:
• ‘.’ 表示他们可以通过的空地。
• ‘#’ 表示他们无法通过的区域。
• ‘*’ 表示在该地下,可以找到黄金。。。
令小明高兴的是,他的朋友对不属于他的东西没有任何兴趣,当然包括脚下
的黄金。。。那样所有的黄金就都可以属于小明了。。。
但是他的朋友也有一个要求,他在地图上设置了一系列集结点,取名为'A', 'B' ... 'Z', 'a', 'b' ... 'z'(它们是按照顺序的,并且最多不超过52个)他们从'A'出发。在任意时刻,小明的朋友都会选择一条最短的路,达下一个集结点休息。小明可以选择和他一样的路径,也可以选择其他的,但是,必须同时到达。小明对于宝藏的渴望,使得他浑身充满了力量,在到达下一个集结点前,可以在路上选择一个有黄金的地点,几乎不需时间就可以把它挖出来,当然这股力量不会积累,即每次休息过后至多只能挖出一个黄金。挖出黄金的地点自动变成‘.’,不可能再长出黄金来。
那么小明想要知道,在服从朋友的要求下,他最多能挖出多少个宝藏。
Input
第一行两个整数R和C。(2<=R,C<=100)表示地图的行和列数。
接下来R行,每行C个字符,表示地图的状态。仅包含‘A’ ? ‘Z’ or ‘a’ ? ‘z’ or ‘.’ or ‘#’ or ‘*’。
Output
一个整数,表示小明能获得的最多宝藏数,如果有一个集结点无法到达,则输出-1。
Sample Input
Sample Output
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<deque>
using namespace std;
struct node{
int x,y;
}sss[60];
deque<node>sp;
char map[105][105],ss[55];
int n,m,sx,sy,ex,ey,viss[105][105],sea[60][10005],visss[105][105],match[10005],vis[10005],num;
int dirx[4]={0,0,1,-1},diry[4]={1,-1,0,0};
bool dfs(int u){//二分图匹配
for(int v=1;v<=n*m;v++){
if(sea[u][v]&&!vis[v]){
vis[v]=1;
if(match[v]==-1||dfs(match[v])){
match[v]=u;
return true;
}
}
}
return false;
}
int main(){
int i,j;
for(i=1;i<=26;i++)ss[i]=i+'A'-1;
for(i=27;i<=52;i++)ss[i]=i-27+'a';//每个目标点
while(scanf("%d%d",&n,&m)!=EOF){
char c='A';
int flag=1;
memset(sea,0,sizeof(sea));
for(i=1;i<=n;i++){
scanf("%s",map[i]+1);
for(j=1;j<=m;j++){
if(map[i][j]=='A'){//起点
sx=i;
sy=j;
}
if(map[i][j]!='*'&&map[i][j]!='#'&&map[i][j]!='.'&&map[i][j]>c){
c=map[i][j];//终点的字母
}
if(map[i][j]>='B'&&map[i][j]<='Z'){//每个目标点的位置
sss[map[i][j]-'A'+1].x=i;
sss[map[i][j]-'A'+1].y=j;
}
if(map[i][j]>='a'&&map[i][j]<='z'){
sss[map[i][j]-'a'+27].x=i;
sss[map[i][j]-'a'+27].y=j;
}
}
}
if(c>='a')num=c-'a'+27;
else num=c-'A'+1;//有多少目标点
for(i=1;i<num;i++){
memset(viss,0,sizeof(viss));
memset(visss,0,sizeof(visss));
int dis=0;
sp.clear();
sp.push_back((node){sx,sy});
viss[sx][sy]=1;
while(!sp.empty()){//第一次bfs,找出距离
node f=sp.front();
sp.pop_front();
int x=f.x;
int y=f.y;
if(map[x][y]==ss[i+1]){//找到这次bfs的终点
dis=viss[x][y]+1;//距离定为+1,假设起点为1,终点为10,那么第二次bfs起点为1,终点为10,10+1=11,所以是dis=距离+1
sx=x;
sy=y;
}
for(j=0;j<4;j++){
int px=x+dirx[j],py=y+diry[j];
if(px>=1&&px<=n&&py>=1&&py<=m&&map[px][py]!='#'&&!viss[px][py]){
viss[px][py]=viss[x][y]+1;
sp.push_back((node){px,py});
}
}
}
if(viss[sss[i+1].x][sss[i+1].y]==0){//如果不能到达下一个目标点
flag=0;
break;
}
sp.push_back((node){sx,sy});
visss[sx][sy]=1;
while(!sp.empty()){//第二次bfs
node f=sp.front();
sp.pop_front();
int x=f.x;
int y=f.y;
if(visss[x][y]+viss[x][y]>dis)continue;//如果当前点已经不是最短路的点,那就continue掉
if(map[x][y]=='*'){//如果当前是最短路点且当前点是宝藏,那么就建一条边
sea[i][(x-1)*m+y]=1;
}
for(j=0;j<4;j++){
int px=x+dirx[j],py=y+diry[j];
if(px>=1&&px<=n&&py>=1&&py<=m&&map[px][py]!='#'&&!visss[px][py]){
visss[px][py]=visss[x][y]+1;
sp.push_back((node){px,py});
}
}
}
}
if(!flag){//如果无法到达某一个集结点
printf("-1\n");
continue;
}
int sum=0;
memset(match,-1,sizeof(match));
for(j=1;j<num;j++){//二分图匹配
memset(vis,0,sizeof(vis));
if(dfs(j))sum++;
}
printf("%d\n",sum);
}
return 0;
}