题意:有一个矩阵,某些格有人,某些格有房子,每个人可以上下左右移动,问给每个人进一个房子,所有人需要走的距离之和最小是多少。

貌似以前见过很多这样类似的题,都不会,现在知道是用KM算法做了

KM算法目前还没弄懂,先套模板做

Sample Input

2 2
.m
H.
5 5
HH..m
.....
.....
.....
mm..H
7 8
...H....
...H....
...H....
mmmHmmmm
...H....
...H....
...H....
0 0

Sample Output

2
10
28
 #include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
const int MAXN=;
const int INF=0x3fffffff;
int g[MAXN][MAXN],match1[MAXN],match2[MAXN];
int KM(int m,int n)
{
int i,j,k,p,q;
int l1[MAXN],l2[MAXN];
int s[MAXN],t[MAXN];
int ret=;
for(i=;i<m;i++)
{
l1[i]=-INF;
for(j=;j<n;j++)
if(g[i][j]>l1[i])
l1[i]=g[i][j];
if(l1[i]==-INF) return -;//无法匹配
}
for(i=;i<n;i++)l2[i]=; memset(match1,-,sizeof(match1));
memset(match2,-,sizeof(match2));
for(i=;i<m;i++)
{
memset(t,-,sizeof(t));
for(s[p=q=]=i;p<=q&&match1[i]<;p++)
for(k=s[p],j=;j<n&&match1[i]<;j++)
if(l1[k]+l2[j]==g[k][j]&&t[j]<)
{
s[++q]=match2[j],t[j]=k;
if(s[q]<)
for(p=j;p>=;j=p)
match2[j]=k=t[j],p=match1[k],match1[k]=j;
} if(match1[i]<)
{
for(i--,p=INF,k=;k<=q;k++)
for(j=;j<n;j++)
if(t[j]<&&l1[s[k]]+l2[j]-g[s[k]][j]<p)
p=l1[s[k]]+l2[j]-g[s[k]][j]; for(j=;j<n;j++)if(t[j]>=)l2[j]+=p;
for(k=;k<=q;k++)l1[s[k]]-=p;
}
}
for(i=;i<m;i++)
{
if(match1[i]<)return -;//无法匹配
if(g[i][match1[i]]<=-INF)return -;
ret+=g[i][match1[i]];
}
return ret;
}
struct Node
{
int x,y;
};
Node node1[MAXN],node2[MAXN];
char str[MAXN];
int main()
{
int n,m;
int nx,ny;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==&&m==)break;
nx=;
ny=;
for(int i=;i<n;i++)
{
scanf("%s",&str);
for(int j=;j<m;j++)
{
if(str[j]=='m')
{
node1[nx].x=i;
node1[nx].y=j;
nx++;
}
else if(str[j]=='H')
{
node2[ny].x=i;
node2[ny].y=j;
ny++;
}
}
}
for(int i=;i<nx;i++)
for(int j=;j<ny;j++)
{
g[i][j]=-abs(node1[i].x-node2[j].x)-abs(node1[i].y-node2[j].y);
}
printf("%d\n",-KM(nx,ny));
}
return ;
}
 /*
POJ 2195 Going Home
邻接矩阵形式最小费用最大流
*/ #include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std; //************************************************************
//最小费用最大流算法
//SPFA求最短路
//邻接矩阵形式
//初始化:cap:容量,没有边为0
//cost:耗费,对称形式,没有边的也为0
//c是最小费用
//f是最大流
//*******************************************************
const int MAXN=;
const int INF=0x3fffffff;
int cap[MAXN][MAXN];//容量,没有边为0
int flow[MAXN][MAXN];
//耗费矩阵是对称的,有i到j的费用,则j到i的费用为其相反数
int cost[MAXN][MAXN]; int n;//顶点数目0~n-1
int f;//最大流
int c;//最小费用
int start,end;//源点和汇点 bool vis[MAXN];//在队列标志
int que[MAXN];
int pre[MAXN];
int dist[MAXN];//s-t路径最小耗费
bool SPFA()
{
int front=,rear=;
for(int u=;u<=n;u++)
{
if(u==start)
{
que[rear++]=u;
dist[u]=;
vis[u]=true;
}
else
{
dist[u]=INF;
vis[u]=false;
}
}
while(front!=rear)
{
int u=que[front++];
vis[u]=false;
if(front>=MAXN)front=;
for(int v=;v<=n;v++)
{
if(cap[u][v]>flow[u][v]&&dist[v]>dist[u]+cost[u][v])
{
dist[v]=dist[u]+cost[u][v];
pre[v]=u;
if(!vis[v])
{
vis[v]=true;
que[rear++]=v;
if(rear>=MAXN)rear=;
}
}
}
}
if(dist[end]>=INF)return false;
return true;
} void minCostMaxflow()
{
memset(flow,,sizeof(flow));
c=f=;
while(SPFA())
{
int Min=INF;
for(int u=end;u!=start;u=pre[u])
Min=min(Min,cap[pre[u]][u]-flow[pre[u]][u]);
for(int u=end;u!=start;u=pre[u])
{
flow[pre[u]][u]+=Min;
flow[u][pre[u]]-=Min;
}
c+=dist[end]*Min;
f+=Min;
}
}
//************************************************************ struct Node
{
int x,y;
};
Node node1[MAXN],node2[MAXN];
char str[MAXN][MAXN];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int N,M;
while(scanf("%d%d",&N,&M))
{
if(N==&&M==)break;
int tol1=,tol2=;
for(int i=;i<N;i++)
{
scanf("%s",&str[i]);
for(int j=;j<M;j++)
{
if(str[i][j]=='m')
{
tol1++;
node1[tol1].x=i;
node1[tol1].y=j;
}
else if(str[i][j]=='H')
{
tol2++;
node2[tol2].x=i;
node2[tol2].y=j;
}
}
}
start=;
n=tol1+tol2+;
end=tol1+tol2+;
memset(cap,,sizeof(cap));
memset(cost,,sizeof(cost));
for(int i=;i<=tol1;i++)
{
cost[][i]=cost[i][]=;
cap[][i]=;
}
for(int i=;i<=tol2;i++)
{
cost[tol1+i][end]=;
cap[tol1+i][end]=;
}
for(int i=;i<=tol1;i++)
for(int j=;j<=tol2;j++)
{
cost[i][tol1+j]=abs(node1[i].x-node2[j].x)+abs(node1[i].y-node2[j].y);
cost[tol1+j][i]=-cost[i][tol1+j];
cap[i][tol1+j]=;
}
minCostMaxflow();
printf("%d\n",c);
}
return ;
}
 /*
POJ 2195 Going Home
邻接表形式最小费用最大流
*/ #include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std; const int MAXN=;
const int MAXE=;
const int INF=0x3f3f3f3f;
struct Edge
{
int from;
int to;
int next;
int re;//记录逆边的下标
int cap;//容量
int cost;//费用
}edge[MAXE];
int pre[MAXN];
int head[MAXN];
bool vis[MAXN];
int que[MAXN];
int dist[MAXN];
int tol;//边的总数
void add(int u,int v,int ca,int co)
{
edge[tol].from=u;
edge[tol].to=v;
edge[tol].cap=ca;
edge[tol].cost=co;
edge[tol].re=tol+;
edge[tol].next=head[u];
head[u]=tol++; edge[tol].from=v;//加逆边
edge[tol].to=u;
edge[tol].cap=;
edge[tol].cost=-co;
edge[tol].re=tol-;
edge[tol].next=head[v];
head[v]=tol++;
}
int n;
int start;
int end;
bool SPFA()
{
int front=,rear=;
for(int v=;v<=n;v++)
{
if(v==start)
{
que[rear++]=v;
vis[v]=true;
dist[v]=;
}
else
{
dist[v]=INF;
vis[v]=false;
}
}
while(front!=rear)
{
int u=que[front++];
vis[u]=false;
if(front>=MAXN)front=;
for(int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].to;
if(edge[i].cap&&dist[v]>dist[u]+edge[i].cost)
{
dist[v]=dist[u]+edge[i].cost;
pre[v]=i;
if(!vis[v])
{
que[rear++]=v;
vis[v]=true;
if(rear>=MAXN)rear=;
}
}
}
}
if(dist[end]==INF)return false;
return true;
}
int c;//费用
int f;//最大流 void minCostMaxflow()
{
c=f=;
int u,p;
while(SPFA())
{
int Min=INF;
for(u=end;u!=start;u=edge[p].from)
{
p=pre[u];
Min=min(Min,edge[p].cap);
}
for(u=end;u!=start;u=edge[p].from)
{
p=pre[u];
edge[p].cap-=Min;
edge[edge[p].re].cap+=Min; }
c+=dist[end]*Min;
f+=Min;
}
} struct Node
{
int x,y;
};
Node node1[MAXN],node2[MAXN];
char str[MAXN][MAXN];
int main()
{
// freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int N,M;
while(scanf("%d%d",&N,&M))
{
if(N==&&M==)break;
int tol1=,tol2=;
for(int i=;i<N;i++)
{
scanf("%s",&str[i]);
for(int j=;j<M;j++)
{
if(str[i][j]=='m')
{
tol1++;
node1[tol1].x=i;
node1[tol1].y=j;
}
else if(str[i][j]=='H')
{
tol2++;
node2[tol2].x=i;
node2[tol2].y=j;
}
}
}
start=;
n=tol1+tol2+;
end=tol1+tol2+; //加边之前一定要初始化
tol=;//边数
memset(head,-,sizeof(head));//一定要初始化为-1 for(int i=;i<=tol1;i++)
{
add(,i,,);
}
for(int i=;i<=tol2;i++)
{
add(tol1+i,end,,);
}
for(int i=;i<=tol1;i++)
for(int j=;j<=tol2;j++)
{
int temp=abs(node1[i].x-node2[j].x)+abs(node1[i].y-node2[j].y);
add(i,tol1+j,,temp);
}
minCostMaxflow();
printf("%d\n",c);
}
return ;
}

poj 2195 二分图带权匹配+最小费用最大流的更多相关文章

  1. POJ 2195:Going Home(最小费用最大流)

    http://poj.org/problem?id=2195 题意:有一个地图里面有N个人和N个家,每走一格的花费是1,问让这N个人分别到这N个家的最小花费是多少. 思路:通过这个题目学了最小费用最大 ...

  2. POJ 2195 & HDU 1533 Going Home(最小费用最大流)

    这就是一道最小费用最大流问题 最大流就体现到每一个'm'都能找到一个'H',但是要在这个基础上面加一个费用,按照题意费用就是(横坐标之差的绝对值加上纵坐标之差的绝对值) 然后最小费用最大流模板就是再用 ...

  3. 二分图带权匹配 KM算法与费用流模型建立

    [二分图带权匹配与最佳匹配] 什么是二分图的带权匹配?二分图的带权匹配就是求出一个匹配集合,使得集合中边的权值之和最大或最小.而二分图的最佳匹配则一定为完备匹配,在此基础上,才要求匹配的边权值之和最大 ...

  4. 二分图带权匹配、最佳匹配与KM算法

    ---------------------以上转自ByVoid神牛博客,并有所省略. [二分图带权匹配与最佳匹配] 什么是二分图的带权匹配?二分图的带权匹配就是求出一个匹配集合,使得集合中边的权值之和 ...

  5. hdu 1569 &1565 (二分图带权最大独立集 - 最小割应用)

    要选出一些点,这些点之间没有相邻边且要求权值之和最大,求这个权值 分析:二分图带权最大独立集. 用最大流最小割定理求解.其建图思路是:将所有格点编号,奇数视作X部,偶数视作Y部,建立源点S和汇点T, ...

  6. [hdu1533]二分图最大权匹配 || 最小费用最大流

    题意:给一个n*m的地图,'m'表示人,'H'表示房子,求所有人都回到房子所走的距离之和的最小值(距离为曼哈顿距离). 思路:比较明显的二分图最大权匹配模型,将每个人向房子连一条边,边权为曼哈顿距离的 ...

  7. 经典网络流题目模板(P3376 + P2756 + P3381 : 最大流 + 二分图匹配 + 最小费用最大流)

    题目来源 P3376 [模板]网络最大流 P2756 飞行员配对方案问题 P3381 [模板]最小费用最大流 最大流 最大流问题是网络流的经典类型之一,用处广泛,个人认为网络流问题最具特点的操作就是建 ...

  8. 【二分图带权匹配】Anagram @山东省第九届省赛 A

    题目描述 Orz has two strings of the same length: A and B. Now she wants to transform A into an anagram o ...

  9. [poj] 3422 Kaka's Matrix Travels || 最小费用最大流

    原题 给一个N*N的方阵,从[1,1]到[n,n]走K次,走过每个方格加上上面的数,然后这个格上面的数变为0.求可取得的最大的值. 要求最大值,所以把边权全为负跑最小费用即可.因为只有第一次经过该点的 ...

随机推荐

  1. HTML 5 应用程序缓存

    使用 HTML5,通过创建 cache manifest 文件,可以轻松地创建 web 应用的离线版本. 什么是应用程序缓存(Application Cache)? HTML5 引入了应用程序缓存,这 ...

  2. safeNet

    把那4个dll丢到C:\Windows\SysWOW64里去重启IIS,再测试

  3. ResultSet

    在Java中,获得ResultSet的总行数的方法有以下几种. 第一种:利用ResultSet的getRow方法来获得ResultSet的总行数 Java代码Statement stmt = con. ...

  4. 不使用配置文件动态注册HttpModule

    在asp.net 4.0中,提供了一种不通过修改配置文件注册Module的方法.从.net3.5开始,新提供的PreApplicationStartMethodAttribute特性可以应用在程序集上 ...

  5. 实现JavaScript自定义函数的整合、链式调用及类的封装

    函数声明形式:表单验证函数 1 2 3 4 5 6 7 8 9 10 11 12 13 function checkName(){     console.log('检查用户名'); } functi ...

  6. Word Amalgamation(枚举 + 排序)

    Word Amalgamation Time Limit: 1 Sec  Memory Limit: 64 MB Submit: 373  Solved: 247 Description In mil ...

  7. Java中的向上转型和向下转型

    首先要明白一点向上转型和向下转型他们都是建立在继承的基础上. 一.向上转型 子类到父类的转换通常称作向上转型,通俗的说就是定义父类对象指向子类对象. 下面通过一个例子来深入理解向上转型. //定义一个 ...

  8. java笔记--关于int和byte[]的转换

    关于int和byte[]数组的转换 --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3891747.html "谢谢-- 众所 ...

  9. IOS 入门开发之创建标题栏UINavigationBar的使用(二)

    IOS 入门开发之创建标题栏UINavigationBar的使用 http://xys289187120.blog.51cto.com/3361352/685746     IOS 开发有关界面的东西 ...

  10. [Educational Codeforces Round 16]A. King Moves

    [Educational Codeforces Round 16]A. King Moves 试题描述 The only king stands on the standard chess board ...