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 ;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-07 10:40:03

hdu3468 Treasure Hunting 二分匹配的相关文章

poj 2594 Treasure Exploration (二分匹配)

Treasure Exploration Time Limit: 6000MS   Memory Limit: 65536K Total Submissions: 6558   Accepted: 2644 Description Have you ever read any book about treasure exploration? Have you ever see any film about treasure exploration? Have you ever explored

HDU 3641 Treasure Hunting (二分+分解质因子)

题目链接:HDU 3641 Treasure Hunting 题意:求X!%M==0中最小的的X.其中M=a1^b1*a2^b2*a3^b3.... 思路:求余为0想到整除,即分母的因子构成的集合是分子的因子构成的集合的子集.因子又想到,任何一个整数都可以分解成若干个素数相乘. 注意:题目数据很大,查到答案时二分. AC代码: #include<stdio.h> #include<string.h> #define ll __int64 bool Prime[210]; ll nu

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

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 3468 Treasure Hunting(BFS+网络流之最大流)

题目地址:HDU 3468 这道题的关键在于能想到用网络流.然后还要想到用bfs来标记最短路中的点. 首先标记方法是,对每一个集合点跑一次bfs,记录所有点到该点的最短距离.然后对于任意一对起始点来说,只要这个点到起点的最短距离+该点到终点的最短距离==起点到终点的最短距离,就说明这点在某条从起点到终点的最短路上. 然后以集合点建X集,宝物点建Y集构造二分图,将从某集合点出发的最短路中经过宝物点与该集合点连边.剩下的用二分匹配算法或最大流算法都可以.(为什么我的最大流比二分匹配跑的还要快....

kuangbin带你飞 匹配问题 二分匹配 + 二分图多重匹配 + 二分图最大权匹配 + 一般图匹配带花树

二分匹配:二分图的一些性质 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图. 1.一个二分图中的最大匹配数等于这个图中的最小点覆盖数 König定理是一个二分图中很重要的定理,它的意思是,一个二分图中的最大匹配数等于这个图中的最小点覆盖数.如果你还不知道什么是最小点覆盖,我也在这里说一下:假如选

二分匹配学习(转载)

先了解一下基本的知识: 转自:http://blog.sina.com.cn/s/blog_89a06c7d0100trcg.html 二分图: 二分图又称二部图,是图论中的一种特殊模型.设G=(V,E)是一个无向图,如果顶点V可以分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A, j in B), 则称图G是二分图. 匹配: 给定一个二分图,在G的一个子图G'中,如果G'的边集中的任意两条边都不依附于同一个顶点,则称G

HDU 3641 Treasure Hunting (素数拆分)

题意:有N个ai,bi,M=a1^b1*a2^b2*a3^b3-*an^bn ,求最小的 x 使得 x! % M ==0. 思路:把M分成多个素数相乘,num[i] 记录素数 i 的个数,然后二分找到x,若 x! 中所有 i 的个数满足>=num[i] 即为答案. #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #in

HDU 3641 Treasure Hunting

用二分查找来找到一个X使得满足X!%M==0 M=a1^b1*a2^b2*a3^b3-*an^bn X!=1*2*3*4*5....*X; M可以化为其个个质因子的k次方的乘积 例如 2^3*3^2*4^5==2^13*3^2; X!则可以得到 例如 2的次方为 X! = 2^(X/2)*(1*2*3*4*5*6*7....*X/2)*other=(x/2)! *other; 继续计算知道x/2==1为止 得到次方数:再与输入的数比较 输入的ai,bi 计算并储存好个个质数的次方 #includ