UVa:10888 Warehouse

问题可以转化为二分图匹配来做。利用BFS求得每个X到每个B的最短距离,为权值。

然后用KM算法求最小权。需要用求最大权的算法,权值取反。

不存在无解的情况。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#define ll long long
#define INF 2139062143
#define inf -2139062144
#define MOD 20071027
#define MAXN 100
using namespace std;
bool visx[MAXN],visy[MAXN];
int lx[MAXN],ly[MAXN],w[MAXN][MAXN],slack[MAXN];
int link[MAXN];
int nx,ny;
bool find(int x)
{
    visx[x]=true;
    for(int y=1; y<=ny; ++y)
        if(!visy[y])
        {
            int t=lx[x]+ly[y]-w[x][y];
            if(t==0)
            {
                visy[y]=true;
                if(link[y]==-1||find(link[y]))
                {
                    link[y]=x;
                    return true;
                }
            }
            else slack[y]=min(slack[y],t);
        }
    return false;
}
int KM()
{
    memset(link,-1,sizeof(link));
    memset(lx,0x80,sizeof(lx));
    memset(ly,0,sizeof(ly));
    for(int i=1; i<=nx; ++i)
        for(int j=1; j<=ny; ++j)
            lx[i]=max(lx[i],w[i][j]);

    for(int x=1; x<=nx; ++x)
    {
        memset(slack,0x7f,sizeof(slack));
        while(1)
        {
            memset(visx,0,sizeof(visx));
            memset(visy,0,sizeof(visy));
            if(find(x)) break;
            int d=INF;
            for(int y=1; y<=ny; ++y)
                if(!visy[y]&&d>slack[y])
                    d=slack[y];
            for(int i=1; i<=nx; ++i)
                if(visx[i]) lx[i]-=d;
            for(int i=1; i<=ny; ++i)
                if(visy[i]) ly[i]+=d;
                else slack[i]-=d;
        }
    }
    int res=0;
    for(int i=1; i<=ny; ++i)
        if(link[i]!=-1)
            res+=w[link[i]][i];
    return res;
}
char grid[MAXN][MAXN];
int flag[MAXN][MAXN];
int mx,my;
struct Point
{
    int x,y,s;
};
int M[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};
int BFS(int sx,int sy)
{
    queue<Point> que;
    bool vis[MAXN][MAXN]= {0};
    vis[sx][sy]=true;
    que.push(Point {sx,sy,0});
    int u=flag[sx][sy];
    while(!que.empty())
    {
        Point q=que.front();
        if(grid[q.x][q.y]=='B') w[u][flag[q.x][q.y]]=min(w[u][flag[q.x][q.y]],q.s);
        que.pop();
        for(int i=0; i<4; ++i)
        {
            int ex=q.x+M[i][0],ey=q.y+M[i][1];
            if(ex<1||ey<1||ex>mx||ey>my) continue;
            if(vis[ex][ey]||grid[ex][ey]=='#') continue;
            vis[ex][ey]=true;
            que.push(Point {ex,ey,q.s+1});
        }
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&mx,&my);
        for(int i=1; i<=mx; ++i)
            scanf("%s",grid[i]+1);
        nx=ny=0;
        memset(flag,0,sizeof(flag));
        for(int i=1; i<=mx; ++i)
            for(int j=1; grid[i][j]; ++j)
                if(grid[i][j]=='B') flag[i][j]=++ny;
                else if(grid[i][j]=='X') flag[i][j]=++nx;
        memset(w,0x7f,sizeof(w));
        for(int i=1; i<=mx; ++i)
            for(int j=1; grid[i][j]; ++j)
                if(grid[i][j]=='X')
                    BFS(i,j);
        for(int i=1; i<=nx; ++i)
            for(int j=1; j<=ny; ++j)
                w[i][j]=-w[i][j];
        int res=KM();
        printf("%d\n",-res);
    }
    return 0;
}


 

你可能感兴趣的:(bfs,二分图,KM算法)