【HDU 3468 Treasure Hunting】(二分匹配+bfs最短路好题)

Problem Description
Do you like treasure hunting? Today, with one of his friend, iSea is on a venture trip again. As most movie said, they find so many gold hiding in their trip.
Now iSea’s clever friend has already got the map of the place they are going to hunt, simplify the map, there are three ground types:

● '.' means blank ground, they can get through it
● '#' means block, they can’t get through it
● '*' means gold hiding under ground, also they can just get through it (but you won’t, right?)

What makes iSea very delighted is the friend with him is extraordinary justice, he would not take away things which doesn’t belong to him, so all the treasure belong to iSea oneself! 
But his friend has a request, he will set up a number of rally points on the map, namely 'A', 'B' ... 'Z', 'a', 'b' ... 'z' (in that order, but may be less than 52), they start in 'A', each time friend reaches to the next rally point in the shortest way, they have to meet here (i.e. iSea reaches there earlier than or same as his friend), then start together, but you can choose different paths. Initially, iSea’s speed is the same with his friend, but to grab treasures, he save one time unit among each part of road, he use the only one unit to get a treasure, after being picked, the treasure’s point change into blank ground.
Under the premise of his friend’s rule, how much treasure iSea can get at most?

 

Input
There are several test cases in the input.

Each test case begin with two integers R, C (2 ≤ R, C ≤ 100), indicating the row number and the column number.
Then R strings follow, each string has C characters (must be ‘A’ – ‘Z’ or ‘a’ – ‘z’ or ‘.’ or ‘#’ or ‘*’), indicating the type in the coordinate.

The input terminates by end of file marker.
 

Output
For each test case, output one integer, indicating maximum gold number iSea can get, if they can’t meet at one or more rally points, just output -1.

 

Sample Input
 
  
2 4A.B.***C2 4A#B.***C
 

Sample Output
 
  
12


链接:http://acm.hdu.edu.cn/showproblem.php?pid=3468

题意:有A~Z或者a~z的字母,按顺序走,寻找宝藏,每次只能走相邻字母间的最短路,如果此最短路上有宝藏可以hunt,获取后该地点变成空地,若相邻两点的最短路上有多个宝藏,则只能选一个(一开始没有读懂“ he save one time unit among each part of road, he use the only one unit to get a treasure”,一直无法理解题意)。求最大的能找到的宝藏数

分析:没相邻两点之间的最短路之间的多个宝藏只能选择一个,求最大的宝藏数”。对于一个点,如果它到下一个点的的最短路上有宝藏,那么说明这个点是可以到达这个宝藏点的,但是这样就可以直接取了吗?显然不是的,有可能因为这个点被取了,导致其他相邻顶点的最短路本来可以取到这个宝藏却因为被拿走了而不能取,显然这就是一个二分图最大匹配问题了。我们把字母点最为左边集合,把宝藏作为右边的集合。那么如何解决建图呢?显然,如果我们一个字母到下一个字母的最短路中有宝藏点,说明这个点是可以匹配。而最短路的判断通过bfs预处理记录长度,最后建图的时候通过dis[i][go[i+1]]=dis[i][gold[j]]+dis[i+1][gold[j]],来判断是否能够建边;

吐槽一下自己坑自己的点:

1.数组开小了(却是wa)

2.没有弄清数组中的维度代表什么意思,导致改了很久的bug

3.数组标记的顺序从0/1开始?又改了很久

4.memset(dis[x],0,sizeof(dis[x]));没有注意到bfs时每次只要初始化最小要处理开始st的所有值,导致答案一开始一直出不来

55555555555555555555555555怀疑人生分界线555555555555555555555555555555



代码:

#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <list>
#include <numeric>
#include <sstream>
#include <limits>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define pb push_back

using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair<string, int> psi;
typedef pair<string, string> pss;

const double PI = acos(-1.0);
const double E = exp(1.0);
const double eps = 1e-30;

const double INFD = 1e20;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int INF = 0x3f3f3f3f;
const int maxn = (int)1e2 + 27;
const int MAXN = (int)1e2 + 10;
const int MOD = (int)1e9 + 7;

int g[maxn][maxn];
int linker[maxn*maxn];
int used[maxn*maxn];
int vis[maxn*maxn];
char s[maxn][maxn];
int gold[maxn*maxn];
int go[maxn];
int dis[maxn][maxn*maxn];
int tot;
int mx;
int dr[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int r,c;
vector<int>v[maxn];


int dfs(int x){
	for(int i=0;i<v[x].size ();i++){
		int j=v[x][i];
		if(!used[j]){
			used[j]=1;
			if(linker[j]==-1||dfs(linker[j])){
				linker[j]=x;
				return 1;
			}
		}
	}
	return 0;
}

int hungry(){
	int res=0;
	CLR(linker,-1);
	for(int i=1;i<=mx;i++){
		CLR(used,0);
		if(dfs(i)){
			res++;
		}
	}
	return res;
}

int judge(char x){
	if(isalpha(x)){
		if(x>='A'&&x<='Z')return x-'A'+1;
		if(x>='a'&&x<='z')return x-'a'+1+26;
	}
	return 0;
}

int bfs(int st){
	CLR(vis,0);
	CLR(dis[st],INF);
	queue<int>q;q.push (go[st]);
	vis[go[st]]=1;
	dis[st][go[st]]=0;
	while(q.size ()){
		int tmp=q.front ();q.pop();
		int x=(tmp-1)/c;
		int y=(tmp-1)%c;
		for(int i=0;i<4;i++){
			int xx=x+dr[i][0];
			int yy=y+dr[i][1];
			if(xx>=0&&yy>=0&&xx<r&&yy<c){
				int nt=xx*c+yy+1;
				if(s[xx][yy]=='#')continue;
				if(vis[nt])continue;
				q.push (nt);
				vis[nt]=1;
				dis[st][nt]=dis[st][tmp]+1;
			}
		}
	}
	//printf("%d\n",dis[st][go[st+1]]);
	if(st==mx)return 1;
	if(dis[st][go[st+1]]!=INF)return 1;
	else return 0;
}

int main(){
	while(~scanf("%d%d",&r,&c)){
		CLR(go,-1);
		CLR(g,0);
		tot=1;
		mx=0;
		for(int i=0;i<r;++i){
			scanf("%s",s[i]);
			for(int j=0;j<c;++j){
				int t=judge(s[i][j]);
				if(t){
					go[t]=i*c+j+1;//记录字母的位置,从0开始标记路径
					mx=max(mx,t);
				}else if(s[i][j]=='*'){
					gold[tot++]=i*c+j+1;//gold记录宝藏的位置,从0开始标记
				}
			}
		}
		int ok=1;
		for(int i=1;i<=mx;++i){
			if(go[i]==-1){
				ok=0;
				break;
			}
			if(!bfs(i)){
				ok=0;
				break;
			}
		}
		if(!ok){
			printf("-1\n");
			continue;
		}
		//建图
		for(int i=1;i<mx;++i){
			for(int j=1;j<tot;++j){
				if(dis[i][go[i+1]]==dis[i][gold[j]]+dis[i+1][gold[j]]){
					v[i].push_back (gold[j]);
				}
			};
		}
		printf("%d\n",hungry());
		for(int i=1;i<=mx;i++)v[i].clear ();
	}
}

/*

2 4
A.B.
***C
2 4
A#B.
***C
2 4
A#B.
*#*C
3 4
A#B.
..*.
C...
2 4
C#B.
***A
3 5
.A**.
C*...
..B..
output
	1
	2
	-1
	1
	2
	2
*/




猜你喜欢

转载自blog.csdn.net/running_acmer/article/details/80965677
今日推荐