Treasure Hunting (hdu 3468 二分匹配+bfs最短路径)

Treasure Hunting

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)

Total Submission(s): 1509    Accepted Submission(s): 393

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 4
A.B.
***C
2 4
A#B.
***C

Sample Output

1
2

Author

iSea @ WHU

Source

2010 ACM-ICPC Multi-University
Training Contest(3)——Host by WHU

Recommend

zhouzeyong   |   We have carefully selected several similar problems for you:  3467 3461 3462 3464 3465

题意:在一个R*C的地图内,字母表示集合点,‘*’表示宝藏,‘.’表示空地,现在沿着A->....->Z->a->....->z的方向走,途中从一个集合点到下一个集合点之间只能捡一个宝藏,问最后最多能捡多少宝藏。

思路:将集合点和宝藏分别看成两个集合,若在集合点x到y的最短路径上有‘*’,那么就在x和‘*’之间连边。bfs求出所有集合点到下一个集合点的最短路径。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 1005
#define MAXN 2005
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define FRE(i,a,b)  for(i = a; i <= b; i++)
#define FREE(i,a,b) for(i = a; i >= b; i--)
#define FRL(i,a,b)  for(i = a; i < b; i++)
#define FRLL(i,a,b) for(i = a; i > b; i--)
#define mem(t, v)   memset ((t) , v, sizeof(t))
#define sf(n)       scanf("%d", &n)
#define sff(a,b)    scanf("%d %d", &a, &b)
#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
#define pf          printf
#define DBG         pf("Hi\n")
typedef long long ll;
using namespace std;

struct Node
{
    int x,y;
    int step;
};

int dir[4][2]={1,0,-1,0,0,1,0,-1};
int g[60][10005];
int linker[10005];
char mp[105][105];
int id1[105][105],id2[105][105];
int dist1[60][10005],dist2[60][60];
int R,C,uN,vN;
bool used[10005];
bool vis[105][105];

bool dfs(int u)
{
    for (int v=1;v<=vN;v++)
    {
        if (g[u][v]&&!used[v])
        {
            used[v]=true;
            if (linker[v]==-1||dfs(linker[v]))
            {
                linker[v]=u;
                return true;
            }
        }
    }
    return false;
}

int hungary()
{
    int res=0;
    memset(linker,-1,sizeof(linker));
    for (int u=1;u<=uN;u++)
    {
        memset(used,false,sizeof(used));
        if (dfs(u)) res++;
    }
    return res;
}

bool isok(Node a)
{
    if (a.x>=0&&a.x<R&&a.y>=0&&a.y<C) return true;
    return false;
}

void bfs(int sx,int sy)
{
    int minn=INF;
    queue<Node>Q;
    Node st,now;
    while (!Q.empty()) Q.pop();
    st.x=sx;st.y=sy;
    st.step=0;
    memset(vis,false,sizeof(vis));
    vis[sx][sy]=true;
    Q.push(st);
//    printf("%d %d+\n",sx,sy);
    while (!Q.empty())
    {
        st=Q.front(); Q.pop();
        for (int i=0;i<4;i++)
        {
            now.x=st.x+dir[i][0];
            now.y=st.y+dir[i][1];
            now.step=st.step+1;
            if (isok(now)&&mp[now.x][now.y]!='#'&&!vis[now.x][now.y])
            {
//                printf("%d %d\n",now.x,now.y);
                vis[now.x][now.y]=true;
                Q.push(now);
                if (mp[now.x][now.y]=='*')
                    dist1[id1[sx][sy]][id2[now.x][now.y]]=now.step;
                if (id1[now.x][now.y]==id1[sx][sy]+1)
                    dist2[id1[sx][sy]][id1[now.x][now.y]]=now.step;
            }
        }
    }
}

int main()
{
//    freopen("C:/Users/asus1/Desktop/IN.txt","r",stdin);
    int i,j;
    while (~scanf("%d%d",&R,&C))
    {
        int cnt1=0,cnt2=1;
        int have[60];
        memset(have,0,sizeof(have));
        memset(id1,0,sizeof(id1));
        memset(g,0,sizeof(g));
        memset(id2,0,sizeof(id2));
        for (i=0;i<R;i++)
        {
            scanf("%s",mp[i]);
            for (j=0;j<C;j++)
            {
                if (mp[i][j]>='A'&&mp[i][j]<='Z')
                {
                    id1[i][j]=mp[i][j]-'A'+1; //给集合点标号
                    cnt1++;
                    have[id1[i][j]]=1;
                }
                else if (mp[i][j]>='a'&&mp[i][j]<='z')
                {
                    id1[i][j]=mp[i][j]-'a'+27;  //给集合点标号
                    cnt1++;
                    have[id1[i][j]]=1;
                }
                else if (mp[i][j]=='*')
                    id2[i][j]=cnt2++;   //给宝藏标号
            }
        }
        for (i=1;i<=cnt1;i++)  //若集合点中间断层了直接输出-1
            if (!have[i]) break;
        if (i<=cnt1){
            printf("-1\n");
            continue;
        }
        for (i=0;i<cnt1+10;i++)
            for (j=0;j<cnt1+10;j++)
                dist2[i][j]=-1;  //dist2[i][[j]表示集合点i到集合点j的最短距离
        for (i=0;i<cnt1+10;i++)
            for (j=0;j<cnt2+10;j++)
                dist1[i][j]=-1; //dist1[i][j]表示集合点i到宝藏j的最短距离
        int flag=1;
        for (i=0;i<R;i++)
        {
            for (j=0;j<C;j++)
            {
                if (id1[i][j])
                    bfs(i,j);
            }
        }
        for (i=1;i<cnt1;i++) //若有两个集合点之间不可到达直接输出-1
            if (dist2[i][i+1]==-1){
                flag=0;
                break;
            }
        if (!flag)
        {
//            DBG;
            printf("-1\n");
            continue;
        }
//        DBG;
        for (i=0;i<R;i++)//建图
        {
            for (j=0;j<C;j++)
            {
                if (id1[i][j])
                {
                    for (int k=1;k<cnt2;k++)
                    {
                        if (dist1[id1[i][j]][k]+dist1[id1[i][j]+1][k]==dist2[id1[i][j]][id1[i][j]+1])
                            g[id1[i][j]][k]=1;
                    }
                }
            }
        }
        uN=cnt1;vN=cnt2-1;
        printf("%d\n",hungary());
    }
    return 0;
}
时间: 2024-08-24 00:32:50

Treasure Hunting (hdu 3468 二分匹配+bfs最短路径)的相关文章

hdu 3641 Treasure Hunting 强大的二分

1 /** 2 大意:给定一组ai,bi . m = a1^b1 *a2^b2 * a3^ b3 * a4^b4*...*ai^bi 3 求最小的x!%m =0 4 思路: 将ai 质因子分解,若是x!%m=0 那么x! 质因子分解之后 质因子的个数一定大于等于m的个数.二分求解可得 5 注意: 二分时,需要将,上下限 设定好,low =0: high = 1ll<<60; 6 **/ 7 8 #include <iostream> 9 #include <cstring&g

Hdu 2389 二分匹配

题目链接 Rain on your Parade Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 655350/165535 K (Java/Others)Total Submission(s): 2644    Accepted Submission(s): 823 Problem Description You’re giving a party in the garden of your villa by the sea. T

hdu 4169 二分匹配最大独立集 ***

题意:有水平N张牌,竖直M张牌,同一方向的牌不会相交.水平的和垂直的可能会相交,求最少踢出去几张牌使剩下的牌都不相交. 二分匹配 最小点覆盖=最大匹配. 链接:点我 坐标点作为匹配的端点 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #incl

hdu 5093 二分匹配

/* 题意:给你一些冰岛.公共海域和浮冰,冰岛可以隔开两个公共海域,浮冰无影响 求选尽可能多的选一些公共海域点每行每列仅能选一个. 限制条件:冰山可以隔开这个限制条件.即*#*可以选两个 预处理: ***** **#*# ***** 可以按行转化 ***** **#oo ooo*# ***** 按列转化 ***o**o **ooooo oooo*oo **o**o* 因为每行每列顶多可以增加50 所以总共最多2500*2500的矩阵 然后直接二分匹配即可 */ #include<stdio.h>

Battle ships HDU - 5093二分匹配

Battle shipsHDU - 5093 题目大意:n*m的地图,*代表海洋,#代表冰山,o代表浮冰,海洋上可以放置船舰,但是每一行每一列只能有一个船舰(类似象棋的車),除非同行或者同列的船舰中间有冰山挡着,问最多能放多少个船舰? 之前做过一个放置炮的,那时数据小直接暴力加搜索就A了,然而这题暴力搜索的话,直接了当的TLE,没办法只好去学新东西了.二分图这个概念只有在之前的题目中做过匈牙利的板子题,可是具体概念和思路并不了解,这题也正好提醒了我去深入了解.但最近需要做的事情较大,一直想整理的

HDU 3641 Treasure Hunting(阶乘素因子分解+二分)

题目链接:传送门 题意: 求最小的 ( x! ) = 0 mod (a1^b1*a2^b2...an^bn) 分析: 首先吧a1~an进行素因子分解,然后统计下每个质因子的指数,由于随着x的增大,质因子的个数是逐渐增加的 因此我们可以二分x,对x!进行素因子分解判断是否满足条件,然后求出最小的就可以了. 代码如下: #include <iostream> #include <cstring> #include <algorithm> #include <cstdi

HDU 5090 二分匹配

Game with Pearls Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 172    Accepted Submission(s): 103 Problem Description Tom and Jerry are playing a game with tubes and pearls. The rule of the g

hdu 4685 二分匹配+强连通分量

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4685 题解: 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<vector> 5 #include<stack> 6 #include<algorithm> 7 using namespace std; 8 9 const int maxn =

HDU 3729 二分匹配匈牙利算法

I'm Telling the Truth Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1482    Accepted Submission(s): 740 Problem Description After this year’s college-entrance exam, the teacher did a survey in