原题:http://acm.hdu.edu.cn/showproblem.php?pid=3468
题意:
给定一个n*m的地图;
.表示空地,#表示墙,*表示黄金;
从A走到Z或者从a走到z;
要求每次都按最短路走到下一个字母,且走的字母是连续的;
若走不到下一个字母或者地图上不存在下一个字母就输出-1;
每次走到下一个字母的途中可以拿一个黄金,问最多可以得到多少个黄金;
思路:
尽量从每个字母走出来都能取一个黄金,二分匹配;
把起点字母作为X集,黄金作为Y集,映射为黄金在起点到终点的最短路上;
而黄金在最短路上所要满足的条件为:起点到终点的距离 = 起点到黄金的距离+终点到黄金的距离;
#include<stdio.h>
#include<queue>
#include<vector>
#include<string.h>
#include<iostream>
#include<algorithm>
const int N = 110;
using namespace std;
int n, m;
int num, k;
int dis[N][N*N], poi[N*N], r[N], gold[N*N]; //r表示字母在poi中的编号;
char s[N][N];
bool vis[N*N], used[N*N];
int match[N*N];
int f[4][2] = {-1, 0, 0, 1, 1, 0, 0, -1};
vector<int>G[N];
void bfs(int u)
{
memset(vis, false, sizeof(vis));
memset(dis[u], -1, sizeof(dis[u]));
queue<int>q;
vis[poi[u]] = true;
dis[u][poi[u]] = 0;
q.push(poi[u]);
while(!q.empty())
{
int l = q.front();
q.pop();
int x = l/m;
int y = l%m;
for(int i = 0;i<4;i++)
{
int a = x+f[i][0];
int b = y+f[i][1];
int now = a*m+b;
if(s[a][b] == '#') continue;
if(a<0 || b<0 || a>=n || b>=m) continue;
if(vis[now]) continue;
vis[now] = true;
dis[u][now] = dis[u][l]+1;
q.push(now);
}
}
}
bool solve(int x)
{
for(int i = 0;i<G[x].size();i++)
{
int v = G[x][i];
if(!used[v])
{
used[v] = true;
if(match[v] == -1||solve(match[v]))
{
match[v] = x;
return true;
}
}
}
return false;
}
int find(char c)
{
if(c>='A' && c<='Z')
return c-'A';
if(c>='a' && c<='z')
return c-'a'+26;
}
int main()
{
while(scanf("%d%d", &n, &m)!=EOF)
{
k = num = 0;
memset(r, -1, sizeof(r));
for(int i = 0;i<n;i++)
{
scanf("%s", s[i]);
for(int j = 0;j<m;j++)
{
if(isalpha(s[i][j]))
{
poi[k] = i*m+j;
r[find(s[i][j])] = k;
k++;
}
if(s[i][j] == '*')
gold[num++] = i*m+j;
}
}
for(int i = 0;i<k;i++)
{
bfs(i);
G[i].clear();
}
int i;
for(i = 0;i<k-1;i++)
{
if(r[i] == -1 || r[i+1] == -1)
break;
if(dis[r[i]][poi[r[i+1]]] == -1)
break;
}
if(i!=k-1)
{
printf("-1\n");
continue;
}
for(int i = 0;i<k-1;i++)
{
for(int j = 0;j<num;j++)
{
if(dis[r[i]][gold[j]] == -1 || dis[r[i+1]][gold[j]] == -1)
continue;
if(dis[r[i]][gold[j]]+dis[r[i+1]][gold[j]] == dis[r[i]][poi[r[i+1]]])
G[i].push_back(j);
}
}
memset(match, -1, sizeof(match));
int sum = 0;
for(int i = 0;i<k-1;i++)
{
memset(used, false, sizeof(used));
if(solve(i))
sum++;
}
printf("%d\n", sum);
}
return 0;
}