HDOJ 3468 Treasure Hunting (BFS+DFS+匈牙利算法) 综合性好题,好题!!!

来源:互联网 发布:已知数据求标准误 编辑:程序博客网 时间:2024/05/21 00:48


Treasure Hunting

TimeLimit: 4000/2000 MS (Java/Others)    Memory Limit:131072/65536 K (Java/Others)
Total Submission(s): 2000    Accepted Submission(s): 544

Problem Description

Do you liketreasure hunting? Today, with one of his friend, iSea is on a venture tripagain. 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 tohunt, 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 (butyou 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 treasurebelong to iSea oneself!
But his friend has a request, he will set up a number of rally points on themap, namely 'A', 'B' ... 'Z', 'a', 'b' ... 'z' (in that order, but may be lessthan 52), they start in 'A', each time friend reaches to the next rally pointin the shortest way, they have to meet here (i.e. iSea reaches there earlierthan or same as his friend), then start together, but you can choose differentpaths. Initially, iSea’s speed is the same with his friend, but to grabtreasures, he save one time unit among each part of road, he use the only oneunit to get a treasure, after being picked, the treasure’s point change intoblank ground.
Under the premise of his friend’s rule, how much treasure iSea can get at most?

 

 

Input

Thereare several test cases in the input.

Each test case begin with two integers R, C (2 ≤ R, C ≤ 100), indicating therow 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 testcase, output one integer, indicating maximum gold number iSea can get, if theycan’t meet at one or more rally points, just output -1.

 

 

Sample Input

2 4

A.B.

***C

2 4

A#B.

***C

 

 

Sample Output

1

2



题意:iSea和他的朋友去寻宝,范围为r*c的矩阵,'.'表示空地,可以在上面经过,'#'表示障碍,不能从上面经过 ,' * '表示上面有宝藏,宝藏只能拿一次,拿过后这个地方就变成了空地。iSea的朋友不会拿走任何宝藏,但有一个要求,地图上有的地方有'A' ~ 'Z','a' ~ 'z'这些字母中的一个,他们必须要按照顺序经过这些地方,如果中间有地方中断了,iSea就不能获得任何宝藏。而且他们每走到其中一个点必须会合,且他的朋友走的是最短路,每走一步需要一个单位时间,iSea由于要找宝藏,他在每条路径上会节省一个单位时间(如A到B,B到C),但是他拿宝藏也需要一个单位时间。问他们从A出发最多能拿到多少宝藏?

思路:

  1. 显然,由于每段路径只节省了一个单位时间,刚好为拿宝藏所需时间,故iSea也必须走最短路,又因为每条路径上最多拿一个宝藏,故想到用匈牙利算法求最大匹配数。
  1. 求最短路自然而然想到用BFS,先定起点为A,终点为B找最短路,然后更新起点为B,终点为C,以此类推。由于要找最短路径上是否有宝藏,我们需要在BFS的时候记录路径,可以用一个step数组,yongstep[i][j]来表示(i,j)到起点的距离,显然我们在BFS时对于下一个搜到的点(ii,jj)有step[ii][jj]=step[i][j]+1.
  1. 每次找到最短路后,从终点开始用DFS回溯,判断下一个点(ii,jj)是否为当前点(i,j)的前驱的依据是step[ii][jj]=step[i][j]-1.由于要进行匈牙利二分匹配,将路径标号与格子编号(坐标为(x,y)的点的标号为x*c+y+1)建边.
  1. 跑一个二分匹配的模板即可。


#include <cstdio>#include <cmath>#include <iostream>#include <queue>#include <cstring>#include <algorithm>using namespace std;#define mst(a,b) memset((a),(b),sizeof(a))#define f(i,a,b) for(int i=(a);i<=(b);++i)#define rush() int T;scanf("%d",&T);while(T--)typedef long long ll;const int maxn= 105;const ll mod = 1e9+7;const int INF = 0x3f3f3f3f;const double eps = 1e-6;const int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};int r,c,sx,sy;int head[maxn*maxn];int match[maxn*maxn];bool vis[maxn][maxn];bool vis2[maxn*maxn];int step[maxn][maxn];char mp[maxn][maxn];int cnt,tot;struct point{    int x,y;}now,nex;struct node{    int u,v,next;}e[maxn*maxn*52];bool inbound(point a){    return a.x>=0&&a.x<r&&a.y>=0&&a.y<c;}void add(int u,int v){    e[cnt].v=v;    e[cnt].next=head[u];    head[u]=cnt++;}int bfs(int x,int y)                      //找最短路径{    mst(step,0);    step[x][y]=1;    queue<point>q;    now.x=sx;    now.y=sy;    q.push(now);    while(q.size())    {        now=q.front();        q.pop();        if(mp[now.x][now.y]==mp[x][y]+1||mp[now.x][now.y]=='a'&&mp[x][y]=='Z')        {            sx=now.x;                   //更新起点            sy=now.y;            return 1;        }        for(int i=0;i<4;i++)        {            nex.x=now.x+dir[i][0];            nex.y=now.y+dir[i][1];            if(inbound(nex)&&step[nex.x][nex.y]==0&&mp[nex.x][nex.y]!='#')            {                step[nex.x][nex.y]=step[now.x][now.y]+1;                q.push(nex);            }        }    }    return 0;}void dfs(int x,int y)               //回溯找路径上的宝藏{    if(mp[x][y]=='*')    {        add(tot,x*c+y+1);    }    vis[x][y]=1;    for(int i=0;i<4;i++)    {        nex.x=x+dir[i][0];        nex.y=y+dir[i][1];        if(inbound(nex)&&vis[nex.x][nex.y]==0&&step[nex.x][nex.y]==step[x][y]-1/*&&mp[nex.x][nex.y]!='#'*/)        {            dfs(nex.x,nex.y);        }    }}bool find(int now)               {    for(int i=head[now];~i;i=e[i].next)    {        int v=e[i].v;        if(vis2[v]==0)        {            vis2[v]=1;            if(match[v]==-1||find(match[v]))            {                match[v]=now;                return 1;            }        }    }    return 0;}int solve()                      //二分匹配求最大匹配数{    mst(match,-1);    int ans=0;    for(int i=0;i<tot;i++)    {        mst(vis2,0);        if(find(i)) ans++;    }    return ans;}int main(){    while(~scanf("%d%d",&r,&c))    {        int sum=0;        cnt=0;        mst(head,-1);        for(int i=0;i<r;i++)        {            scanf("%s",mp[i]);            for(int j=0;j<c;j++)            {                if(mp[i][j]=='A')                {                    sx=i;                    sy=j;                }                if(mp[i][j]>='A'&&mp[i][j]<='Z'||mp[i][j]>='a'&&mp[i][j]<='z')                      sum++;            }        }        sum--;        tot=0;        while(1)        {            int temp=bfs(sx,sy);            if(temp)            {                mst(vis,0);                dfs(sx,sy);                sum--;                tot++;            }            else break;        }        if(sum==0)        {            printf("%d\n",solve());        }        else puts("-1");                 //路径不连通    }    return 0;}


阅读全文
0 0