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

貌似以前见过很多这样类似的题,都不会,现在知道是用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. [LeetCode] Binary Tree Preorder/Inorder/Postorder Traversal

    前中后遍历 递归版 /* Recursive solution */ class Solution { public: vector<int> preorderTraversal(Tree ...

  2. Database Password Hashes

    SQL Server 2000:- SELECT password from master.dbo.sysxlogins where name=’sa’ 0×010034767D5C0CFA5FDCA ...

  3. eq相等 ne、neq不相等, gt大于, lt小于 gte、ge大于等于 lte、le 小于等于 not非 mod求模 等

    eq相等   ne.neq不相等,   gt大于, lt小于 gte.ge大于等于   lte.le 小于等于   not非   mod求模   is [not] div by是否能被某数整除   i ...

  4. ios开发 <AppName>-Prefix.pch文件的用法详解

    我们知道,每新建立一个工程,比如说HelloWord,在分类SupportingFiles里都会有一个以工程名开头-Prefix.pch结尾的文件,如HelloWord-Prefix.pch.对于这个 ...

  5. SVN服务器搭建--Subversio与TortoiseSVN的配置安装

    SVN服务器搭建和使用(一) Subversion是优秀的版本控制工具,其具体的的优点和详细介绍,这里就不再多说. 首先来下载和搭建SVN服务器. 现在Subversion已经迁移到apache网站上 ...

  6. 10 steps to becoming the developer everyone wants

    You thought it was all about programming skills. But you were wrong! Great code is fine, yet command ...

  7. Scheme笔记(1)

    (define pi 3.14159) (define radius 10) (* pi (* radius radius)) (define circumference (* 2 pi radius ...

  8. [Effective JavaScript 笔记]第38条:在子类的构造函数中调用父类的构造函数

    示例 场景类 场景图(scene)是在可视化的过程中(如游戏或图形仿真场景)描述一个场景的对象集合.一个简单的场景包含了在该场景中的所有对象(称角色),以及所有角色的预加载图像数据集,还包含一个底层图 ...

  9. WinAPI: ExtCreateRegion - 区域变换

    转载:http://www.cnblogs.com/del/archive/2008/06/03/1212534.html 相似函数: SetWorldTransform 本例效果图: 代码文件: u ...

  10. django-cms 代码研究(二)bugs?

    djangocms集成到现有项目中后,发现了几个问题: 1. 现有项目的url匹配失效,下面requests请求被交给djangocms处理了 url(r'^admin/', include(admi ...