hdu3468 Treasure Hunting 二分匹配

//给一个n*m的图
//.表示空白地
//*表示有黄金
//#表示墙
//一个人需要按照A...Z..a..z的顺序以最短路径走到下一个
//每次只能在他的路线上经过的地方取一块黄金
//问最多能取多少黄金
//对于每次起点和终点,用bfs搜索最短路,再用dfs找出最短路线经过的所有点
//对于第i次找最短路线与其走过的点建立边,然后用二分匹配就能找出
#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std ;
const int maxn = 110 ;
vector<int> vec[maxn] ;
int match[maxn*maxn] ;
int vis[maxn][maxn] ;
int visit[maxn*maxn] ;
char map[maxn][maxn] ;
int pos[maxn*maxn] ;int len ;
int st_x , st_y , en_x, en_y ;
int dx[4] = {0 , 1 , 0 , -1} ;
int dy[4] = {1 , 0 , -1 , 0} ;
int n , m ;
queue<int> que ;
int sum = 0 ;
void dfs(int x , int y , int num)
{
    sum++ ;
    if(x == st_x && y == st_y)
    return ;
    if(map[x][y] == '*')
        vec[num].push_back(x*m+y) ;
    for(int i = 0;i < 4;i++)
    {
        int nx = x + dx[i] ;
        int ny = y + dy[i] ;
        if(nx < 0 || nx >= n || ny < 0 || ny >= m || vis[nx][ny] + 1 != vis[x][y])
        continue ;
        dfs(nx , ny ,num);
    }
    vis[x][y] = 0 ;
}
int bfs(int num)
{
    while(que.size())que.pop() ;
    memset(vis, 0  ,sizeof(vis)) ;
    que.push(st_x) ;que.push(st_y) ;
    vis[st_x][st_y] = 1;
    while(que.size())
    {
        int x = que.front() ; que.pop() ;
        int y = que.front() ; que.pop() ;
        if(x == en_x && y == en_y)
        {
            dfs(x , y ,num) ;
            return true ;
        }
        int step = vis[x][y] ;
        for(int i = 0;i < 4;i++)
        {
            int nx = dx[i] + x ;
            int ny = dy[i] + y ;
            if(nx < 0 || nx >= n || ny < 0 || ny >= m || vis[nx][ny] || map[nx][ny] == '#')
            continue ;
            vis[nx][ny] = vis[x][y] + 1 ;
            que.push(nx);
            que.push(ny) ;
        }
    }
   return false ;
}
int find(int u)
{
    for(int i = 0;i < vec[u].size() ;i++)
    {
        int v = vec[u][i] ;
        if(!visit[v])
        {
            visit[v] = 1 ;
            if(match[v] == -1 || find(match[v]))
            {
                match[v] = u ;
                return true ;
            }
        }
    }
    return false ;
}
int Match()
{
    int ans = 0 ;
    memset(match , -1 , sizeof(match)) ;
    for(int i = 0;i < len - 1;i++)
    {
        memset(visit ,0 , sizeof(visit)) ;
        if(find(i))
        ans++ ;
    }
    return ans ;
}
int main()
{
    //freopen("in.txt" ,"r" , stdin) ;
    while(~scanf("%d%d" ,&n , &m))
    {
        memset(pos ,0 , sizeof(pos)) ;
        len = 0 ;
        for(int i = 0;i < n;i++)
        {
            scanf("%s" , &map[i]) ;
            for(int j = 0;j < m;j++)
            if((map[i][j] >= 'a'&&map[i][j] <='z'))
            pos[map[i][j]-'a'+26] = i*m + j +1,len++ ;
            else if(map[i][j] >= 'A' && map[i][j] <= 'Z')
            pos[map[i][j]-'A'] = i*m + j + 1, len++ ;
        }
        int flag = 0 ;
        for(int i = 0;i < len;i++)
        {
            if(!pos[i])
            flag = 1 ;
            pos[i]--;
        }
        if(len < 2 || flag)
        {
            puts("-1");
            continue ;
        }
        for(int i = 0;i < len - 1;i++)
        {
            vec[i].clear() ;
            st_x = pos[i]/m;st_y = pos[i]%m;
            en_x = pos[i+1]/m;en_y = pos[i+1]%m ;
            if(!bfs(i))
            {
                flag = 1;
                break ;
            }
        }
        if(flag)puts("-1") ;
        else
        printf("%d\n" , Match()) ;
    }
    return 0 ;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值