HDU1533Going Home(KM匹配之最小值匹配)

题意:求最小花费。KM通常是来求最大完美匹配,这里只需要把权重变为负数。最后再变回来即可


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<set>
#include<map>
#include<string>
#include<cstring>
#include<stack>
#include<queue>
#include<vector>
#include<cstdlib>
#define lson (rt<<1),L,M
#define rson (rt<<1|1),M+1,R
#define M ((L+R)>>1)
#define cl(a,b) memset(a,b,sizeof(a));
#define LL long long
#define P pair<int,int>
#define X first
#define Y second
#define pb push_back
#define fread(zcc)  freopen(zcc,"r",stdin)
#define fwrite(zcc) freopen(zcc,"w",stdout)
using namespace std;
const int maxn=305;
const int inf=999999;

int w[maxn][maxn];
int linker[maxn],lx[maxn],ly[maxn],slack[maxn];
bool visx[maxn],visy[maxn];
int nx,ny;

bool dfs(int x){
    visx[x]=true;
    for(int y=1;y<=ny;y++){
        if(visy[y])continue;
        int tmp=lx[x]+ly[y]-w[x][y];
        if(tmp==0){
            visy[y]=true;
            if(linker[y]==-1||dfs(linker[y])){
                linker[y]=x;
                return true;
            }
        }else if(slack[y]>tmp){
            slack[y]=tmp;
        }
    }
    return false;
}
int km(){
    cl(linker,-1);
    cl(ly,0);
    for(int i=1;i<=nx;i++){
        lx[i]=-inf;
        for(int j=1;j<=ny;j++)if(w[i][j]>lx[i]){
            lx[i]=w[i][j];
        }
    }
    for(int x=1;x<=nx;x++){
        fill(slack,slack+ny+1,inf);
        while(true){
            cl(visx,false);
            cl(visy,false);
            if(dfs(x))break;
            int d=inf;
            for(int i=1;i<=ny;i++)if(!visy[i]&&d>slack[i]){
                d=slack[i];
            }
            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 ans=0;
    for(int i=1;i<=ny;i++)if(linker[i]!=-1){
        ans+=w[linker[i]][i];
    }
    return ans;
}
char a[maxn][maxn];
P h[maxn],mm[maxn];
inline int abs(int s){return s<0?-s:s;}
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)&&n+m){
        int num1=1,num2=1;
        for(int i=1;i<=n;i++){
            scanf("%s",a[i]);
            for(int j=0;j<m;j++){
                if(a[i][j]==‘H‘){
                    h[num1].X=i;
                    h[num1++].Y=j;
                }
                if(a[i][j]==‘m‘){
                    mm[num2].X=i;
                    mm[num2++].Y=j;
                }
            }
        }
        //printf("===%d   %d\n",num1,num2);
        for(int i=1;i<num1;i++){
            for(int j=1;j<num2;j++){
                w[i][j]=abs(h[i].X-mm[j].X)+abs(h[i].Y-mm[j].Y);
                w[i][j]=-w[i][j];
            }
        }
        nx=ny=num2-1;
        printf("%d\n",-km());
    }
    return 0;
}

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

时间: 2024-10-12 01:32:29

HDU1533Going Home(KM匹配之最小值匹配)的相关文章

【POJ 2400】 Supervisor, Supervisee(KM求最小权匹配)

[POJ 2400] Supervisor, Supervisee(KM求最小权匹配) Supervisor, Supervisee Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2538   Accepted: 719 Description Suppose some supervisors each get to hire a new person for their department. There are N

ural 1076 KM求最小权匹配

贴模板~ KM算法引进了顶标函数,不断缩小这个顶标来让相等子图的可能范围扩大 #include<iostream> #include<cstring> //KM 复杂度O^3 using namespace std; const int N=200; int lx[N],ly[N];//顶标函数 int w[N][N];//图 bool vix[N],viy[N]; int linky[N];// int lack;//每次顶标函数扩大的增量 int n,m; bool find(

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

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

空三匹配和密集匹配的区别与联系

很多人包括一些业内人士都不清楚空三匹配(空中三角测量中的连接点匹配,亦即计算机视觉中的SFM算法中的同名点匹配,比如SIFT算法)和密集匹配(也叫立体匹配,立体对应或稠密匹配)有什么区别,于是经常会问诸如下列问题: 1. 做空三匹配的时候做的密集一点就是密集匹配了吧? 2. 空三匹配做完定向后就可以得到正射影像了吧? 3. 用sift也可以做密集匹配吧? 殊不知,以上三个问题的答案都是:NO! 下面我们就来说明一下空三匹配和密集匹配有什么区别和联系. 1. 定义 空三匹配:在空中三角测量(SFM

WildcardMatching和Regex,通配符匹配和正则表达式匹配

WildcardMatching:通配符匹配 算法分析: 1. 二个指针i, j分别指向字符串.匹配公式. 2. 如果匹配,直接2个指针一起前进. 3. 如果匹配公式是*,在字符串中依次匹配即可. 注意记录上一次开始比较的位置 Implement wildcard pattern matching with support for '?' and '*' '?' Matches any single character. '*' Matches any sequence of character

perl学习之:肯定匹配和否定匹配

tr/ / / 替换操作符不支持正则表达式 也不具备双引号替换能力m/ /  s/ / / 都支持正则表达式,并且可以提供或限制双引号替换能力 $string = "25abc8";$string =~ /abc(?=[0-9])/;(?=pattern) 前看声明,如果正则表达式在下一次匹配 pattern 风格,就开始匹配,而且不影响匹配效果.如/\w+(?=\t)/将匹配制表符是否恰好在一个字\w+后面出现,并且制表符不添加到$&的值中:$matched = $&

perl学习之:理解贪婪匹配和最小匹配之间的区别

正则表达式的新手经常将贪婪匹配和最小匹配理解错误.默认情况下,Perl 的正则表达式是“贪婪地”,也就是说它们将尽可能多地匹配字符. 下面的脚本打印出“matched defgabcdef”,因为它尽可能多地匹配模式,直至结尾的‘g’. $data = 'abcdefgabcdefg';$data =~ /abc(.+)g/i;print "matched "; 要改变匹配特点,只须简单地在量词(加号[+]或星号[*])后面加一个问号(?)即可.在上面的程序中把模式改为在‘+’之后包含

jQuery中,选择器既匹配开头又匹配结尾

jQuery中,选择器既匹配开头又匹配结尾的方法: 1 [attr^=val]attr$=val 2 [attr^=val][attr$=val]

javascript正则表达式之最长匹配(贪婪匹配)和最短匹配(懒惰匹配)

最近在阅读RequireJS 2.1.15源码,源码开始处定义了一系列的变量,有4个正则表达式: var commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, currDirRegExp = /^\.\//; comment