★ HDU 3468 最短路+二分匹配

本文介绍了一种基于最短路径算法求解特定问题的方法,包括如何构建图模型,使用广度优先搜索(BFS)寻找最短路径,并通过递归深度优先搜索实现匈牙利算法来解决二分图的最大匹配问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分析:求出每个集合点到其他所有点的最短距离,然后枚举每个金子,看他是否在两点之间的最短路上,如果在的话,以路径编号和金子在矩阵里的编号(i*m+j)建边。

代码:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <queue>
using namespace std;
const int maxn=10005;
const int maxm=1000005;
const int INF=1000000000;
struct EdgeNode
{
    int to;
    int next;
}edge[maxm];
int head[maxn],cnt;
void add(int x,int y)
{
    edge[cnt].to=y;
    edge[cnt].next=head[x];
    head[x]=cnt++;
}

char g[105][105];
int zs,js,n,m,pre[maxn];
bool v[maxn],vis[105][105];
int bj[maxn],dis[105][maxn];
int zm[maxn],hj[maxn];
int d[5][3]={{-1,0},{1,0},{0,-1},{0,1}};
struct p
{
    int x,y,ct;
    friend bool operator < (p a,p b)
    {
        return a.ct>b.ct;
    }
};

void init()
{
    cnt=0;
    memset(head,-1,sizeof(head));
    memset(bj,-1,sizeof(bj));
    for(int i=0;i<=55;i++)
        for(int j=0;j<=n*m;j++)
            dis[i][j]=INF;
}

int zh(char s)
{
    if(s>='A'&&s<='Z')return s-'A'+1;
    if(s>='a'&&s<='z')return s-'a'+1+26;
}

int yj(int x,int y)
{
    if(x<0||x>=n||y<0||y>=m)return 1;
    return 0;
}

void bfs(int w)
{
    int st=zm[w],t;
    p first,next;
    priority_queue<p>Q;
    memset(vis,0,sizeof(vis));
    first.ct=0; first.x=st/m; first.y=st%m;
    Q.push(first);
    vis[first.x][first.y]=1;
    while(!Q.empty())
    {
        first=Q.top();
        Q.pop();
        for(int i=0;i<4;i++){
            next.x=first.x+d[i][0];
            next.y=first.y+d[i][1];
            next.ct=first.ct+1;
            if(!vis[next.x][next.y]&&!yj(next.x,next.y)&&g[next.x][next.y]!='#')
            {
                vis[next.x][next.y]=1;
                Q.push(next);
                t=next.x*m+next.y;
                dis[w][t]=next.ct;
            }
        }
    }
}

int dfs(int x)
{
    int y;
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
        y=edge[i].to;
        if(!v[y]){
            v[y]=1;
            if(!pre[y]||dfs(pre[y]))
            {
                pre[y]=x;
                return true;
            }
        }
    }
    return false;
}

int erfenpipei()
{
    int sum=0;
    memset(pre,0,sizeof(pre));
    for(int i=1;i<=n;i++)
    {
        memset(v,0,sizeof(v));
        if(dfs(i))sum++;
    }
    return sum;
}

int main()
{
    int i,j,t;
    while(~scanf("%d%d",&n,&m))
    {
        zs=js=0;
        init();
        for(i=0;i<n;i++){
            scanf("%s",g[i]);
            for(j=0;j<m;j++){
                if(g[i][j]=='#')continue;
                if(g[i][j]=='.')continue;
                if(g[i][j]=='*'){
                    hj[++js]=i*m+j;
                }
                else{
                    t=zh(g[i][j]);
                    bj[t]=++zs;
                    zm[t]=i*m+j;
                }
            }
        }
        for(i=1;i<=zs;i++)bfs(i);
        for(i=1;i<zs;i++)
        {
            if(bj[i]==-1||bj[i+1]==-1)break;
            if(dis[i][zm[i+1]]==INF)break;
        }
        if(i<zs){printf("-1\n");continue;}
        else{
            for(i=1;i<zs;i++){
                for(j=1;j<=js;j++){
                    if(dis[i][hj[j]]+dis[i+1][hj[j]]==dis[i][zm[i+1]])
                        add(i,hj[j]);
                }
            }
            n=zs;
            printf("%d\n",erfenpipei());
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值