poj 2195 二分图带权匹配+最小费用最大流
题意:有一个矩阵,某些格有人,某些格有房子,每个人可以上下左右移动,问给每个人进一个房子,所有人需要走的距离之和最小是多少。
貌似以前见过很多这样类似的题,都不会,现在知道是用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 二分图带权匹配+最小费用最大流的更多相关文章
- POJ 2195:Going Home(最小费用最大流)
http://poj.org/problem?id=2195 题意:有一个地图里面有N个人和N个家,每走一格的花费是1,问让这N个人分别到这N个家的最小花费是多少. 思路:通过这个题目学了最小费用最大 ...
- POJ 2195 & HDU 1533 Going Home(最小费用最大流)
这就是一道最小费用最大流问题 最大流就体现到每一个'm'都能找到一个'H',但是要在这个基础上面加一个费用,按照题意费用就是(横坐标之差的绝对值加上纵坐标之差的绝对值) 然后最小费用最大流模板就是再用 ...
- 二分图带权匹配 KM算法与费用流模型建立
[二分图带权匹配与最佳匹配] 什么是二分图的带权匹配?二分图的带权匹配就是求出一个匹配集合,使得集合中边的权值之和最大或最小.而二分图的最佳匹配则一定为完备匹配,在此基础上,才要求匹配的边权值之和最大 ...
- 二分图带权匹配、最佳匹配与KM算法
---------------------以上转自ByVoid神牛博客,并有所省略. [二分图带权匹配与最佳匹配] 什么是二分图的带权匹配?二分图的带权匹配就是求出一个匹配集合,使得集合中边的权值之和 ...
- hdu 1569 &1565 (二分图带权最大独立集 - 最小割应用)
要选出一些点,这些点之间没有相邻边且要求权值之和最大,求这个权值 分析:二分图带权最大独立集. 用最大流最小割定理求解.其建图思路是:将所有格点编号,奇数视作X部,偶数视作Y部,建立源点S和汇点T, ...
- [hdu1533]二分图最大权匹配 || 最小费用最大流
题意:给一个n*m的地图,'m'表示人,'H'表示房子,求所有人都回到房子所走的距离之和的最小值(距离为曼哈顿距离). 思路:比较明显的二分图最大权匹配模型,将每个人向房子连一条边,边权为曼哈顿距离的 ...
- 经典网络流题目模板(P3376 + P2756 + P3381 : 最大流 + 二分图匹配 + 最小费用最大流)
题目来源 P3376 [模板]网络最大流 P2756 飞行员配对方案问题 P3381 [模板]最小费用最大流 最大流 最大流问题是网络流的经典类型之一,用处广泛,个人认为网络流问题最具特点的操作就是建 ...
- 【二分图带权匹配】Anagram @山东省第九届省赛 A
题目描述 Orz has two strings of the same length: A and B. Now she wants to transform A into an anagram o ...
- [poj] 3422 Kaka's Matrix Travels || 最小费用最大流
原题 给一个N*N的方阵,从[1,1]到[n,n]走K次,走过每个方格加上上面的数,然后这个格上面的数变为0.求可取得的最大的值. 要求最大值,所以把边权全为负跑最小费用即可.因为只有第一次经过该点的 ...
随机推荐
- Oracle 10g 和11g r2 下载地址(使用迅雷)
http://www.blogjava.net/wangdetian168/archive/2011/03/01/345428.html 10g http://www.blogjava.net/wa ...
- UrlConnection连接和Socket连接的区别
关于UrlConnection连接和Socket连接的区别,只知道其中的原理如下: 抽象一点的说,Socket只是一个供上层调用的抽象接口,隐躲了传输层协议的细节. urlconnection 基于H ...
- sprintf()函数的用法
sprintf(g_strAppName, "%s",pLast+1); ----------------------------------------------------- ...
- explicit构造函数
explicit构造函数 Explicit Constructors(显式构造函数)收藏 按照默认规定,只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应数据类型的数据转换为该类对象,如下面 ...
- MySQL获取随机数
如何通过MySQL在某个数据区间获取随机数? MySQL本身提供一个叫rand的函数,返回的v范围为0 <= v < 1.0. 介绍此函数的MySQL文档也介绍道,可以通过此计算公式FLO ...
- ReactJS入门学习一
ReactJS入门学习一 阅读目录 React是什么? React如何制作组件? 理解组件属性props 理解页面中如何渲染数据的 理解从服务器端获取数据及理解state的 回到顶部 React是什么 ...
- MATLAB对话框设计[转]
Matlab之对话框 对话框设计:在图形用户界面程序设计中,对话框是重要的信息显示和获取输入数据的用户界面对象. 1.公共对话框: 公共对话框是利用windows资源的对话框,包括文件打开.文件保存. ...
- 使用 Python 创建你自己的 Shell(下)
导读 在上篇中,我们已经创建了一个 shell 主循环.切分了命令输入,以及通过 fork 和 exec 执行命令.在这部分,我们将会解决剩下的问题.首先,cd test_dir2 命令无法修改我们的 ...
- CentOS 7安装Splunk
导读 Splunk是探索和搜索数据的最有力工具,从收集和分析应用程序.Web服务器.数据库和服务器平台的实时可视化海量数据流,分析出IT企业产生的海量数据,安全系统或任何商业应用,给你一个总的见解获得 ...
- Unity3D开发之NGUI点击事件穿透响应处理
http://www.xuebuyuan.com/1936292.html 在使用NGUI 开发2D项目的时候,发现了一个问题,就是如果点出一个菜单,然后点击菜单上面的按钮的时候就会使得按钮下面的物品 ...